Wednesday, March 21, 2012

JAVA 7: WHAT’S NEW

Small Coding Enhancements

1. String Switch-Case:

A serious drawback of Switch-Case was it just worked with expressions that evaluated to int (int, short, byte, char, Enum). Not anymore. Now it can take Strings too. Isn’t is awesome?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
String fruit = "apple";
switch (fruit) {
case "orange":
    System.out.println("Color is Orane");
    break;
case "apple":
    System.out.println("Color is Red");
    break;
case "banana":
    System.out.println("Color is Yellow");
    break;
default:
    System.out.println("Not recognized");
    break;
}

2. Binary Literals

The integral types (byte, short, int, long) can be given values in Binary Number system. Add prefix 0b/0B to the binary representation. Previously only decimal, octal and hexadecimal were supported.
1
int binaryInt= 0b011000011; //No need to convert to Hex

3. Underscores in numeric literals

Large integers values looks unreadable and are sore to eyes. To grasp the value of number, we are left to counting the digits and spacing them in threes in our mind. Java 7 provides for underscore in values, so that they become more readable.
1
2
3
4
//OLD
int soreToEyes = 1236541; //how much is it?
//NEW
int easyToEyes = 1_236_541; //Easy to read

4. Catch Multiple Exceptions

Multiple exceptions can be handled by Single Catch Block, with the help of OR operator(|).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//OLD
try {
  //code
}
catch(Exception1 e1) {
    handleException(e1);
} catch(Exception2 e2) {
    handleException(e2);
}
//NEW
try {
  //code
} catch(Exception1 | Exception2 e) {
    handleException(e)
}

5. Diamond Operator (Type Inference)

Redundancy of Type arguments is eased off. It always seemed to me quite odd to be true. Good that it is gone.
1
2
3
4
5
//OLD
Map<String, Integer> = new HashMap<String, Integer>();
//NEW
Map<String, Integer> = new HashMap<>();
//Compiler is able to infer by the LHS only.

6.Automatic Resource Management (Try with Resource)

Files, I/O streams and other such resources were required to be manually closed by writing repetitive code. Mostly inside finally block.
This has been encapsulated now with try block, which closes the resources for us.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//OLD
FileInputStream inputStream = null;
FileOutputStream outputStream = null;
try {
    inputStream = new FileInputStream("input.txt");
    outputStream = new FileOutputStream("output.txt");
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    try {
        inputStream.close();
        outputStream.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
//NEW
try(inputStream; outputStream) {
    //do something
}
//Consolidated Code in Java 7
try (FileInputStream inputStream = new FileInputStream("input.txt");
    FileOutputStream outputStream = new FileOutputStream("output.txt")) {
    //do something;
} catch (FileNotFoundException | IOException e) {
    e.printStackTrace();
}

Concurrency Utilities Fork/Join Framework

With the advent of multiple processors, the code also need to evolve. We need to write code which can spawn Threads in such a manner so as to take complete use of multiple processors. The idea is to use all available processing power which leads to enhanced performance. No Thread should remain free.
Fork/Join framework is an implementation of ExecutorService. We have a ThreadPool. Tasks are allotted to the worker threads. The difference here is if some thread is free, it will steal the work from a busy thread, thereby maximizing performance.
ForkJoinPool is the implementation of ExecutorService which can run ForkJoinTasks. It is different from other ExecutorServices as the threads in the pool tries to steal the subtasks created by other Tasks (being processed by other threads). It’s like a workaholic employee who ends up doing other people’s work also. In effect it improves firms overall performance.
1
2
ForkJoinPool pool = new ForkJoinPool();
pool.invoke(new SumArray(array, 0, array.length));
SumArray extends ForkJoinTask (RecursiveTask/RecursiveAction). See here the analogy with a simple ThreadPoolExecutor, which requires a Runnable/Callable task.
The SumArray needs to have function compute() (analogous to run()) which will be called post pool.invoke() (analogous to execute()). Also a function invokeAll() is available to the SumArray, which is just like invoke, but takes multiple ForkJoinTasks and assign them to the ForkJoinPool.
1
2
3
4
5
6
7
8
9
10
11
protected void compute() {
        if(length < 1000 ) { //No need to Split the Task
            sumDirectly();
            return;
        }
        //Need to split the Task
        invokeAll(new SumArray(array, 0, length/2),
                new SumArray(array, length/2, length));
}

New Filesystem API: new java.nio.file package

To be true, I have never been a fan of Java I/O Util (java.io). Hopefully with the improved NIO, things might get a little better. Time will tell.
A new class Path (also Paths, FileSystem, FileSystem etc) is introduced (akin to java.io.File), with better features. It is expected to work better across file-systems and operating systems. Path also supports symbolic links.
1
2
3
4
5
6
7
8
9
10
11
12
13
Path workPath = Paths.get("D:\myDir\work.txt");
System.out.println("Nodes: " + workPath .getNameCount());
System.out.println("Name: " + workPath .getFileName());
System.out.println("Root: " + workPath .getRoot());
System.out.println("Parent: " + workPath .getParent());
Files.delete(workPath); //Deletes the File
//Output
Nodes: 2
Name: work.txt
Root: D:
Parent: c:myDir
Next is the File Change Notification in Java 7. I remember working on a manual FileWatcherService wherein, we listen to any incoming files in a directory and taking actions on basis of it. It was a lot of code. This simplifies it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//WatchService is created on the FileSystem.
WatchService  watchService = FileSystems.getDefault().newWatchService();
//Get Path Reference to the Directory to be watched.
Path watchPath = Paths.get("D:\dirToBeWatched");
//Register the watchPath with WatchService
watchPath.register(watchService, ENTRY_CREATE, ENTRY_MODIFY, ENTRY_DELETE);
//Start Listening to Events
while(true) {
        WatchKey key = watchService.take();
        for(WatchEvent<?> event : key.pollEvents()) {
            System.out.println("Event Observed: " + event.kind()
                            + " on Dir " + event.context().toString());
        }
}
//Output
Event Observed: ENTRY_MODIFY on Dir dirToBeWatched

No comments:

Post a Comment