Best of: Java 7

 · 5 min

Java was never the quickest language regarding new features compared to newer languages, but IMHO, this is one of the reasons why most of the enterprise world still depends on it and will in the future.

It’s mostly compatible between versions, long-term support is good, and there are many options to run it on. Even though some of this changed recently since Java 9 and the new release model…

We should always know the complete power of a language we’re using by knowing all the new features and might adapt our coding style. Some things are just syntactic sugar, but other features will help us to reduce and avoid bugs, or get rid of an external dependency, or even increase performance with a simple code change.

Let’s check out the new features!


The try-with-resources statements

Dealing with I/O was quite cumbersome before Java 7. We have to make sure that resources will be closed eventually, even if an exception occurs, so we end up with a finally block:

java
BufferedReader reader = new BufferedReader(...);
try {
    reader.readLine();
    ...
}
finally {
    if (reader != null) {
        reader.close();
    }
}

This was a simplified example; maybe we should also check if the reader isn’t already closed?

With Java 7 and the new try-with-resources statement, we can streamline this code and make it more readable!

java
try (BufferedReader reader = new BufferedReader) {
    reader.readLine();
    ...
}

The magic in the background is the new interface java.lang.AutoClosable which allows the automatic closing of resources at the end of the try-with-resources block.

Multiple resources are also supported, they are close in reversed order of declaration:

java
try (
    BufferedReader reader = new BufferedReader(...);
    BufferedWriter writer = new Files.newBufferedWriter(...)
) {
    ...
}
// After this block first 'writer', then 'reader' will be closed.

The try-with-resources statement is also a normal try-block, so feel free to add catch or finally blocks, they are run after the resources are closed.

Only caveat is exception handling… Of course, the closing of resources can throw exceptions. But what happens if our code in the try block throws an exception AND the closing of the resource throws another one? In this case, Java suppresses the closing exceptions, but they are reachable via #getSurpressed() of the exception, courtesy of java.lang.Throwable.


switch with String literals

Starting with Java 7 the switch statement is capable of handling String literals:

java
String mode = ...
switch (mode) {
    case "DEV":
        ...
        break;
    case "PROD":
        ...
        break;
    case "QA":
        ...
        break;
    default:
        ...
        break;
}

The comparison is case-sensitive . switch statements generate more efficient bytecode compared to lots of chained if-then-else.


Binary literal

I don’t work much with binary in my code, but it’s still a nice addition: integral types (byte, short, int, long) are now as easily declarable as hex-number:

java
// Hex
int asHex = 0x25 // = 35// NEW: Binary
int asBinary = 0b100011 // = 35

We can either use 0b or 0B as a prefix and might left-pad the value with as many zeros as needed.

The advantage here is that you can better visualize and compare binary variables that might have a direct relationship to another, which wouldn’t be visible in another form of representation.


Improved numeric literals

Numeric literals (including the new binary literal) can now be written in a more comprehensible way, with underscores as separators:

java
// OLD
long oldCc = 4111111111111111l;
long oldHex = 0xAAFF23C522;
long oldBinary = 0b111000010111;

// NEW 
long cc = 4111_1111_1111_1111l;
long hex = 0xAA_FF_23_C5_22;
long binary = 0b1110_0001_0111;

Some restrictions occur on the placement of the underscore, though:

  • not at the beginning or end of a number
  • not adjacent to the decimal point
  • not adjacent to prefixes/suffixes (e.g., 0x, f)

Multiple Exceptions

Instead of multiple catch-blocks, we can now catch multiple exception types in a single block. It’s nice to have as many different catch blocks as we might need, but if handling them doesn’t differ we combine them with the pipe symbol |:

java
// OLD
try {
    ...
}
catch (NullPointerException ex) {
    ...
}
catch (IllegalArgumentException ex) {
    ...
}

// NEW
try {
    ...
}
catch (NullPointerException | IllegalArgumentException ex) {
    ...
}

The generated bytecode won’t duplicate any code and will be smaller and more efficient compared to multiple identical catch blocks.


Improved Generic Type Inference for Creation

Generics are great, except for typing them so many types:

java
// OLD
Map<Long, List<String>> map = new HashMap<String, List<String>>();

With Java 7 we don’t need to specify the types on the creation part thanks to the diamond operator <>:

Most likely, your IDE is already removing redundant types, or at least you should configure it this way to remove some noise from your code.


There’s more

Of course, there’s more to Java 7 than just these few new language features.

We should always thrive to embody changes to our toolchain if they provide us with simpler patterns, new features or better performance. Sometimes it might be even worth rewriting some code, but don’t force the new stuff on old code if not needed.