Saturday, July 16, 2011

What's new in Java 7 - Project Coin

What's new in Java 7: Well, its a major version upgrade, there needs to be a lot of things coming up. Of course the most noticeable feature set for a java programmer would be the language level change, i.e. Project Coin. Although the changes are not as major as generics (that came with version 5, which was the time they dropped the "1." from the version number.) or annotations (also came with the same version). But, I guess they are at least as good as auto-boxing.

What is Project Coin: Project Coin or JSR334 is the common JSR that embraces all language level changes that comes in Java 7. I will talk about its features one by one.


String in Switch: I cannot emphasize enough how much I like this feature. Upto version 1.4, the only thing that could be switched on was something implicitly cast to int. From version 5.0, enums also found there place in the switch statement. (To be honest, enums are pretty much born for switch statements, and they were born in version 5.0). Also the wrapper types of primitives that could be implicitly cast to int were also allowed from 5.0, thanks to auto-unboxing. But, we certainly were missing Strings, and here they are. The use of Strings in switch statement are pretty intuitive.

switch(type){
case "Normal":
        System.out.println("Hello");
        break;
case: "Active":
        System.out.println("Hi");
        break;
default:
        System.out.println("Oh! come on!");
}

Te code is self explanatory. The Strings are matched consistently with the equals method.

Binary Literals: How many ways can we write an integer literal in Java - decimal, hexadecimal (with 0x) and octal (with 0). Now, there is one more way, binary, just start with a 0b or 0B.


public class Test{
        public static void main(String [] args){
                int x=0B1101001110101;
                System.out.println(x);
        }
}


Output: 6773

Underscores in Literals: It is difficult to read a large number. That is why people separate the digits of a large number with commas. However, Java language specification developers decided that the underscore character would be the right digit separator in Java. So the following values are all same.

  • 12345
  • 1_2345
  • 1_2_3_4_5
  • 1____2__34___5

Underscores can be used with any numeric literal. There is just one rule of thumb, both sides of the underscore (or sequence of underscores) must be digits. So the following are valid.

  • 12_3.45
  • 1_2e5
  • 1_2.3e5_6
  • 1____2__34___5.1_2.2___3

But the following are illeagal

  • _12
  • 1_2e_5
  • 1_2.3_e5_6
  • ___1__

Also, since octal numbers are represented by a leading 0, an underscore between this zero and the first digit is allowed (for example 0_71). However, underscore is not allowed after 0x in a hexadecimal lateral and after 0b in a binary literal.


Multi-catch: A multi-catch is a catch block with multiple exception types. Exception types are separated by an 'OR' operator represented by the '|' character.

import java.io.*;
public class Test{
        public static void main(String [] args){
                try{
                        //May throw ArrayIndexOutOfBoundsException
                        System.out.println(args[0]); 
                        
                        //May throw FileNotFoundException
                        FileInputStream fin=new FileInputStream(args[0]);
                }catch(ArrayIndexOutOfBoundsException|FileNotFoundException ex){
                        ex.printStackTrace();
                }
        }
}


More Refined Check for Unreachable Code in Re-through: If an exception is re-thrown in the catch block of a try, its type is inferred at the compile time by the actual exception that can propagate instead of the type declared in the catch block. For example, would the following code compile?


import java.io.*;
import java.net.*;
public class Test{
        public static void main(String [] args) throws Exception{
                try{
                        
                        //May throw FileNotFoundException
                        FileInputStream fin=new FileInputStream(args[0]);
                }catch(IOException ex){
                        try{
                            throw ex;
                        }catch(SocketException e){
                            e.printStackTrace();
                        }
                }
        }
}

Yes in version 6.0, but NO in version 7.0. The compiler has just got smarter in version 7. It can see that although the type of ex is IOException, only a FileNotFoundException can be thrown from the try block, and since ex is re-thrown without any assignment to it in the catch block (i.e. it is implicitly final), SocketException is actually never thrown, and hence the inner catch block is unreachable. It is allowed, but discouraged to declare the exception (ex in this case) to be final explicitly with the final keyword.


try with Resources: A lot of try blocks are written so that a resource can be closed in the finally block. Java 7 makes this much easier by creating a try with resources syntax. A try block that is passed a resource, does not need a catch block or a finally block to be syntactically valid. However, if a checked exception is declared to be thrown from the code inside the try block, it must be caught or declared to be thrown.

import java.io.*;
import java.net.*;
public class Test{

    public static class ACloseable implements AutoCloseable{
        public void close() throws Exception{
            System.out.println("Closeable called");
            throw new Exception();
        }
    }
    public static void main(String [] args) {
        try(ACloseable c=new ACloseable()){
            //May throw FileNotFoundException
            FileInputStream fin=new FileInputStream(args[0]);
        }catch(FileNotFoundException ex){
            ex.printStackTrace();
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

What if the close method itself throws an exception. In this case, the exception is supressed and its details are added to the exception stacktrace of the original exception that caused the call of close method. The list of exceptions that the try can throw includes the ones thrown by the close method [This means that the above program would not compile if we forgot to write the second catch block that catches Exception]. The resource passed to the try block are implicitly final. It is allowed, but discouraged, to make it explicitly final with the final keyword.

Now here is a million dollar question, why is the list of exceptions the close method can throw, added to the list of exceptions the try can throw? 'cause anyway the exception would be suppressed, right? Wrong! You see, the resource is closed (i.e. the close method is called) even when no exceptions were thrown inside the try block. In this case, if the close method throws an exception, it needs to get caught.

A number of java core library classes now implements AutoCloseable. The classes java.sql.Connection, java.sql.Statement and java.sql.RecordSet are three of them.


The Diamond Operator - Enhanced Type Inferance for Generic Instance Creation: Take the example of the following code snippet.

List<String> aList=new ArrayList<String>();

Now, since the List is obviously of String type elements, there should be no need the specify this while creating the ArrayList. Java 7 takes care of this using the diamond operator '<>', as shown below.

List<String> aList=new ArrayList<>();

The compiler here automatically infers the type parameter in ArrayList to be String. The following are all allowed.

List<String> aList=new ArrayList<>();
List<?> bList=new ArrayList<>();
List<? extends InputStream> cList=new ArrayList<>();
List<? super InputStream> dList=new ArrayList<>();
List eList=new ArrayList<>();//Discouraged for raw types, but allowed.

However, the <> operator is not allowed with annonymous inner classes. Because in this case, instead of just creating an object, we are also creating a class. Thus the following is not allowed

List eList=new ArrayList<>(){
}; //Not allowed;

Safe Varargs: Varargs is variable number of arguments in the method definition. They came into existence from version 5.0. For example, the following code defines a vararg method and the calls it.

import java.util.*;
import java.io.*;
public class Test{

    
    public static void main(String [] args) {
        printAll("One","Two","Three");
    }
    
    public static void printAll(String ... args){
        for(String arg:args){
            System.out.println(arg);
        }
    }
}

Inside the method, the varargs are treated as an array, so you can iterate on it.

Java compiler gives a warning message if the varargs' type is non-reifiable, because it can lead to some nasty unsafe operations being done, for which, generics cannot guarantee type safety.

Now the question is, what is non-refiable type. A refiable type is a type that do not lose any information after type-errasure of the parameterized types during compilation. That means the following types are refiable. All other types are of course non-reifiable.

  1. It refers to a non-generic type declaration, for example java.lang.String str;
  2. It is a parameterized type in which all type arguments are unbounded wildcards, for example java.util.List<?> list;
  3. It is a raw type, for example, java.util.List list;
  4. It is a primitive type, for example, int i;
  5. It is an array type whose component type is reifiable. For example, String [] arrStr;


Thus the following code will give warnings during compilation.

import java.util.*;
import java.io.*;
public class Test{

    
    public static void main(String [] args) {
        printAll(new ArrayList<String>(), new LinkedList<String>());
    }
    
    public static void printAll(List<String> ... args){
        for(List<String> arg:args){
            System.out.println(arg);
        }
    }
}

But if the programmer is sure nothing wrong is going on, he/she can suppress this warning by using the @SafeVarargs annotation. Thus the following code does not give a warning.

import java.util.*;
import java.io.*;
public class Test{

    
    public static void main(String [] args) {
        printAll(new ArrayList<String>(), new LinkedList<String>());
    }
    
    @SafeVarargs
    public static void printAll(List<String> ... args){
        for(List<String> arg:args){
            System.out.println(arg);
        }
    }
}

4 comments:

Anonymous said...

Great!
Thank you, I have used this article for my OCPJP 7 Exam

Anonymous said...

There is a misspelled annotation @SageVarargs

Unknown said...

I'm assuming SafeVarargs will cause runtime exceptions? ClassCastException, namely?

Debasish Ray Chawdhuri said...

Yes if you pass a different type. For example if you pass a List as one of the arguments and later you had written code to access individual strings. In my example, that would not be the case, because its just printing the List.

Post a Comment