Tuesday, January 24, 2012

Java 7 - Project Coin Decompiled

Hi all, it's time to start writing in 2012. As you may have seen already in other blogs, there are a few changes that can make your developer life a lot easier when programming in Java: diamond operator, Strings in Switch, try with resources, multi catch, etc. In this post (PART I) we are going to see some of the small changes presented in Java 7 Project Coin (JSR 334) and then (in PART II) we are going to decompile them in order to see what's the compiler doing (for educational purposes only).


What you need
NetBeans 7+ or any other IDE that supports Java 7
Diamond Operator
Generics helped us to reduce ClassCastExceptions among other things, but some times it can make the code hard to read. Diamond operator is a really nice change. Imaging that you need to group customers by city. You would need something like this:

//suppose the classes City and Customer exist
...
Map<City,List<Customer>> map = new HashMap<City,List<Customer>>();
...

Now, what if you also need to group the data by country:

//suppose the classes Country, City and Customer exist
...
Map<Country,Map<City,List<Customer>>> map = new HashMap<Country,Map<City,List<Customer>>>();
...

Now, it starts to be very hard to read, right? What if you also need to group by Region?

//suppose the classes Region, Country, City and Customer exist
...
Map<Region,Map<Country,Map<City,List<Customer>>>> map = new HashMap<Region, Map<Country,Map<City,List<Customer>>>>();
...

So what do you think? It's not easy at all to read code like that. Fortunately, the new Diamond Operator helps a lot in the readability of code. The last code can be recoded in Java 7 like this:

//suppose the classes Region, Country, City and Customer exist
...
Map<Region,Map<Country,Map<City,List<Customer>>>> map = new HashMap<>();
...

A lot better!


Strings in Switch
I've been waiting for this a lot!!! I remember the days when I was starting in the Java world and I really needed to use Strings in switch. Well, my  waiting is finally over. In earlier versions of Java you had to write something like this:

//in a class
...
public void stringToNumber(String str)
{
   if(str.equalsIgnoreCase("one"))
   {
      System.out.println(1);
   }
   else if(str.equalsIgnoreCase("two"))
   {
      System.out.println(2);
   }
   else if(str.equalsIgnoreCase("three"))
   {
      System.out.println(3);
   }
}
...

In Java 7 you can write it like this:

//in a class
...
public void stringToNumber(String str)
{
   switch(str)
   {
      case "one":
         System.out.println(1);
         break;
      case "two":   
         System.out.println(2);
         break;   
      case "three":
         System.out.println(3);
         break;
   }
}
...

Even NetBeans has an option to convert it automatically:





Try with resources and Multi Catch
This is a nice enhancement in this version, now you don't have to worry about closing those ResultSets, Statements, FileInputStreams...etc. You just need to use the new try structure and the compiler will care about it for you. You can even create your own classes to be Closeable (this is a new interface) by the new try structure. Following is a classic file access via streams:

//in a class
import java.io.*;
...
public static void copyFile(String path) 
              throws IOException, NullPointerException 
{
        File file = new File(path);

        FileOutputStream fout = null;
        FileInputStream fin = null;
        try {
            try {
                fout = new FileOutputStream("file.dat");
                fin = new FileInputStream(file);

                byte[] bytes = new byte[1024];
                int leido = 0;
                while ((leido = fin.read(bytes)) != -1) {
                    fout.write(bytes, 0, leido);
                }
            } finally {
                if (fout != null) {
                    fout.close();
                }
                if (fin != null) {
                    fin.close();
                }
            }
        } catch (NullPointerException ex) {
            ex.printStackTrace();
            throw ex;
        }catch (IOException ex) {
            ex.printStackTrace();
            throw ex;
        }
    }
...

If you notice, in order to be sure that the opened Streams are being closed once they finish, you have to code a try/finally block and close them by yourself. In Java 7, you can achieve the same behaviour in a better way and with less lines of code using the new try structure and the new NIO.2 classes:

//in a class
import java.nio.file.*;
import java.io.*;
...
public static void copyFile(String src) 
              throws IOException, NullPointerException 
{
        Path path = FileSystems.getDefault().getPath(src);
        
        try (FileOutputStream fout = new FileOutputStream("file.dat")) {
            Files.copy(path, fout);
        } catch (NullPointerException | IOException ex) {
            ex.printStackTrace();
            throw ex;
        }
}
...


Binary literals and underscores in literals
Now you can express an integer as a binary literal, this is ideal when programming low-level APIs, also you can use underscores in order to make your values more readable:

//in a class
...
public static void coin() 
{
   int binaryNum = 0b10; //This is number 2 in binary code

   double value1 = 1000000000; //hard to read?
   double value2 = 1_000_000_000; //Easy to read with Java 7

   double value3 = 0b101010110111; //hard to read?
   double value4 = 0b1010_1011_0111; //Easy to read with Java 7

   double pi = 3.14_15_92; //another example of readability
}
...

So, less code, more productivity and a better code readability that's what Project Coin is about! (Among other things not seen here).

That's it for PART I of this post, in PART II we are going to see what's the compiler doing when we Decompile the code we have seen here.


References:

Overview of JDK 7 Support in NetBeans IDE. NetBeans [online].
Available on Internet: http://netbeans.org/kb/docs/java/javase-jdk7.html
[accessed on January 22 2012].