Java 7 launches – new language features introduced

Java 7 is now officially available as of July 28th 2011. The intent of this blog entry is to introduce the new language features. For further details, consult the Java 7 SDK.

Binary Literals

[Official Docs] Long awaited, Java now allows for integral literals (byte, short, int, and long) to be expressed in binary. This will be very useful in certain niches in the same way that Hex and Octal notation have been.

int binaryinteger = 0b10100001010001011010000101000101;
System.out.println(binaryinteger); //prints 10569121

Underscores in Numeric Literals

[Official Docs] Some nice syntactic sugar for making lengthy numeric literals more readable, arbitrary underscores are now allowed in between digits, with some rules (see Official Docs).

int bignumber = 3_947_201; //3947201
int goalpost = 1____1; //11

Strings in Switch Statements

[Official Docs] String class being the staple datatype that it is, Switch statements now accept String types as the switch and as cases. Subjectively, I don’t favour the Switch construct,  but objectively it is an improvement to the construct and of great use to developers that use Switch.

String mylunch = mealOfTheDay();

switch(mylunch) {
  case "sandwich" :
    System.out.println("Oh I love sandvich!");
    break;
  case "soup" :
    System.out.println(":( it's too hot for this");
    break;
  default :
    System.out.println("Chow time...");
}

It is worth noting Oracle’s claim that in general Switches with Strings will be compiled to more efficient bytecode than the equivalent chained If-statements will.

Type Inference for Generic Instance Creation

[Official Docs] In practice this feature is merely a step towards stripping away some verbosity;  it’s a lot less fancy than it sounds. To fully appreciate this new feature, one should be informed on the topic of Java Generics.

Before Java 7, instantiating a generic class required the parameter used in the variable declaration to be provided to the constructor as well.

List<String> brandnames = new List<String>();

Alright, it’s not a terrible notation but still, an extra hassle. Considering that Java Generics are not covariant it is obvious that we will want to use the same type parameter as that of the variable declaration. Furthermore, Java Generic are dealt with at compile time ; surely the necessary code could be generated behind the scenes. This is where the new feature comes into play, Type Inference. It does just that, inferring the correct type parameter, and here is how to invoke it:

//basic usage of the new type inferring
 List<String> brandnames = new List<>();

//it even works when the type to be inferred is a hierarchy
List<? extends Number> favouritenumbers = new List<>();

Note the empty <> notation. OK so it’s not THAT big of a difference but syntactic sugar allows for ideas to be expressed more easily and every little bit works towards making the language more and more fun to work with.

Try-With-Resources

[Official Docs] The Try/Catch/Finally construct has been updated to reduce boilerplate code concerning the freeing of resources, as well as some of the exception clutter. The Try block now allows for a resource to be declared that will be automatically “cleaned up” after the Try. What’s the cost? The resource must implement a newly introduced interface java.lang.AutoCloseable. Oracle has made the existing java.io.Closeable interface extend the AutoCloseable interface, indirectly retrofitting all of the java.io resources with the autoclosing functionality. Lets compare the old syntax with the new syntax:

//old notation for Trying and closing the resource (buffered reader)
BufferedReader br = new BufferedReader(new FileReader(path));
try {
  return br.readLine();
}
finally {
  //we explicitly close the resource
  if (br != null) br.close();
}

/*
new Java 7 notation for Trying and closing the resource (buffered reader)
notice that there is no code concerning the closing of
the resource, it is done automatically.
*/
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
  //the buffered reader is scoped to the Try block
  return br.readLine();
}

Note that in the former example, any exceptions thrown in the Finally block will be bubbled up while the original exception in the Try block will be suppressed. In the Try-With-Resources block, an exception thrown in the Try-With-Resources block will be bubbled up; exceptions thrown during the autoclosing of the resource will be suppressed.  A full list of suppressed exceptions can be acquired through the caught Exception, using java.lang.Throwable getSupressed().

Also note that multiple resources can be declared within the Try-With-Resources construct as such:

try(
  ZipFile zf = new java.util.zip.ZipFile(zipFileName);
  BufferedReader br = new BufferedReader(new FileReader(path))
){
  //resources zf and br will both be automatically closed
}

Improved Exception Handling

[Official Docs] Java 7 also brings about new syntax in catching exceptions to reduce code duplication, and tweaks the Type Checking of the compiler to allow for more control in how exceptions are re-thrown.

First, let us take a look at catching multiple exceptions. Prior to Java 7 this has been done by chaining Catch blocks, often with similar behaviour in each block. If the exception handling behaviour is more or less the same across multiple exceptions, Java 7’s newly introduced compact notation for catching multiple exceptions is very applicable as follows:

//old notation
try {
}
catch (IOException e) {
  logger.log(e);
catch (SQLException e) {
  logger.log(e);
}

//new Java 7 notation
try {
}
catch (IOException | SQLException e) {
  logger.log(e);
}

Please note Oracle’s claim that the new Java 7 notation will generate smaller bytecode than the older notation will.

Also introduced is an enhancement to the compile-time type checking of the exception mechanism. If the following conditions apply to the exception, an exception caught by a superclass parameter Catch block can be re-thrown and implicitly cast back to its original type.

  • The Try block is able to throw it.
  • There are no other preceding Catch blocks that can handle it.
  • It is a subtype or supertype of one of the Catch clause’s exception parameters.

Consider the following example:

public void rethrowException()
  throws FirstException, SecondException {
  try {
  //FirstException or SecondException may be thrown
  }
  catch (Exception e) {
  /*
  e is of type Exception, but the correct type of
  exception will be bubbled up
  */
  throw e;
  }
}

Notice how despite ‘e’ being cast as type Exception, the compiler will figure out its true type and re-throw it as FirstException or SecondException, whichever its true type is.

Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methods

[Official Docs] This one sounds like quite a mouthful, and in fact it is. Its technicality is far too in-depth to discuss summarily. To be honest its impact will likely be unnoticed by a majority of Java developers and those who care are already aware of the issue that it stipulates. Consider this code however:

String[] strings = String[1];
Object[] objects = strings; //legal through type covariance
objects[0] = new Integer(); //legal through subclassing
String s = strings[0]; //ka-boom

Notice how a runtime error has been introduced through the very rules of Java. In a nutshell, this new compiler warning is intended to draw attention when a similar scenario may occur, but it is more geared towards concerns with Java Generics and Erasure.