Monday, February 16, 2009

New Features in Java Tiger Edition.

J2SE 5.0 is for Ease of Development

Tiger, Tiger burning bright
Like a geek who works all night
What new-fangled bit or byte
Could ease the hacker's weary plight?

One of the major themes targeted by the J2SE 5.0 release is ease of development. J2SE 5.0 provides new enhancements to further ease the development of Java applications and tools. New features such as generics, typesafe enumerated types, autoboxing, and enhanced for loop, are all new features that make using Java to build applications easier.

Tiger Feature List

The Tiger feature list is defined in JSR-176 (J2SE 5.0 (Tiger) Release Content), which serves as an umbrella JSR that only lists APIs defined in other component JSRs. Please see JSR-176 for details about the component JSRs.

The J2SE 5.0 release includes several new language features. The rest of this article discusses these language features and shows how to use them to improve programs.

Generics

To the most despised collections' cast
We'll bid a fond farewell at last
With generics' burning spear
The need for cast will disappear

The Collection interface, which is implemented by all collection classes, suggests that all concrete collections are collections of Objects at runtime. This places a burden on the developer of the calling class by forcing him to know the actual type of the elements in the collections, that can be accomplished by looking at the API or using the reflection API. As an example, consider the following class, Ex1, which creates a collection of two strings and one integer, and then prints out the collection:

Ex1.java

import java.util.*;

public class Ex1 {

private void testCollection() {
List list = new ArrayList();
list.add(new String("Hello world!"));
list.add(new String("Good bye!"));
list.add(new Integer(95));
printCollection(list);
}

private void printCollection(Collection c) {
Iterator i = c.iterator();
while(i.hasNext()) {
String item = (String) i.next();
System.out.println("Item: "+item);
}
}

public static void main(String argv[]) {
Ex1 e = new Ex1();
e.testCollection();
}
}

The problem here is that an explicit cast is required in the printCollection method. This class compiles fine, but throws a CLassCastException at runtime as it attempts to cast an Integer to a String:

Item: Hello world!
Item: Good bye!
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer
at Ex1.printCollection(Ex1.java:16)
at Ex1.testCollection(Ex1.java:10)
at Ex1.main(Ex1.java:23)

Generics, which are also known as parameterized types, provide compile-time typesafety for collections and eliminate the drudgery of casting. Using generics, the Ex1 class above can be written as follows:

Ex2.java

import java.util.*;

public class Ex2 {

private void testCollection() {
List<String> list = new ArrayList<String>();
list.add(new String("Hello world!"));
list.add(new String("Good bye!"));
list.add(new Integer(95));
printCollection(list);
}

private void printCollection(Collection c) {
Iterator<String> i = c.iterator();
while(i.hasNext()) {
String item = i.next();
System.out.println("Item: "+item);
}
}

public static void main(String argv[]) {
Ex2 e = new Ex2();
e.testCollection();
}
}

Now, if you try to compile this code, a compile-time error will be produced, informing you that you cannot add an Integer to a collection of Strings. Therefore, generics enable more compile-time type checking and therefore mismatch errors are caught at compile time rather than at runtime.

You may have already noticed the new syntax used to create an instance of ArrayList (i.e. List<String> list = new ArrayList<String>). ArrayList is now a generic or parameterized type. A parameterized type consists of a class or interface E and a parameter section <T1, T2, ..., Tn>, which must match the number of declared parameters of E, and each actual parameter must be a subtype of the formal parameter's bound types. The following segment of code shows parts of the new class definition for ArrayList:

public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
// ...
}

Here E is a type variable, which is an unqualified identifier. It simply acts as a placeholder for a type to be defined when the list is used.

Java Generics vs. C++ Templates

While generics look like the C++ templates, it is important to note that they are not the same. Generics simply provide compile-time type safety and eliminate the need for casts. The main difference is encapsulation: errors are flagged where they occur and not later at some use site, and source code is not exposed to clients. Generics use a technique known as type erasure as described above, and the compiler keeps track of the generics internally, and all instances use the same class file at compile/run time.

A C++ template on the other hand is just a fancy macro processor; whenever a template class is instantiated with a new class, the entire code for the class is reproduced and recompiled for the new class.

Enhanced for Loop

While Iterators have their uses
They sometimes strangle us like nooses
With enhanced-for's deadly ray
Iterator's kept at bay

The current for statement is quite powerful and can be used to iterate over arrays or collections. However, it is not optimized for collection iteration, simply because the iterator serves no other purpose than getting elements out of the collection. The new enhanced for construct lets you iterate over collections and arrays without using iterators or index variables.

The new form of the for statement has the following syntax:

for (FormalParameter : Expression) Statement

Note that Expression must be an array or an instance of a new interface called java.lang.Iterable, which is meant to ease the task of enabling a type for use with the enhanced for statement. This means that the java.util.Collection now extends the Iterable interface that has the following signature:

package java.lang;

public interface Iterable<E> {
/**
* Returns an iterator over the elements in this collection.
* There are no guarantees concerning the order in which the elements
* are returned (unless this collection is an instance of some class
* that provides such a guarantee).
*
* @return an iterator over the elements in this collection
*/

Iterator<E> iterator();
}

As an example, consider the following method that uses the conventional for statement to iterate over a collection:

// Assume we have an instance of StringBuffer "sb"
public void oldFor(Collection c) {
for(Iterator i = c.iterator(); i.hasNtext(); ) {
String str = (String) i.next();
sb.append(str);
}
}

With the addition of generics, the above segment of code can be rewritten using the enhanced for statement as follows:

// Assume we have an instance of StringBuffer "sb"
public void newFor(Collection<String> c) {
for(String str : c) {
sb.append(str);
}
}

Much cleaner, eh?

The enhanced for statement can be used to iterate over an array. Consider the following segment of code for a method that calculates the sum of the elements in an array:

public int sumArray(int array[]) {
int sum = 0;
for(int i=0;i<array.length;i++) {
sum += array[i];
}
return sum;
}

Using the enhanced for statement, this can be rewritten as:

public int sumArray(int array[]) {
int sum = 0;
for(int i : array) {
sum += i;
}
return sum;
}

The new for statement, however, is not a replacement for counting for loops for arrays. Sometimes, the index variable serves more than just an array index -- when a different traversal order is needed, for example. In addition, the enhanced for construct is a compiler 'trick' and can actually end up being slower when used for large collections.

Many developers are asking why they didn't add the foreach and in so that we can write:

foreach (element in collection)

The fact of the matter is that adding new keywords to a language such as Java is quite costly. In addition, it wouldn't be compatible with existing source code that uses the in keyword, for example, as in System.in. So the whole idea is just to keep things upwardly-compatible.

Autoboxing/Unboxing

When from the collections ints are drawn
Wrapper classes make us mourn
When Tiger comes, we'll shed no tears
We'll autobox them in the ears

Manual conversion between primitive types (such as an int) and wrapper classes (such as Integer) is necessary when adding a primitive data type to a collection. As an example, consider an int being stored and then retrieved from an ArrayList:

list.add(0, new Integer(59));
int n = ((Integer)(list.get(0))).intValue();

The new autoboxing/unboxing feature eliminates this manual conversion. The above segment of code can be written as:

list.add(0, 59);
int total = list.get(0);

However, note that the wrapper class, Integer for example, must be used as a generic type:

List<Integer> list = new ArrayList<Integer>();

Programming language critics may have a lot to say about the autoboxing/unboxing feature. On one hand, Java developers agree that the distinction between primitive data types and references can be burdensome. In a pure object-oriented language there should be no difference between a primitive data type and a reference, as everything is an object. The other issue is that of identity: many think of primitive data types as entities that represent mathematical values, which are different from references.

The purpose of the autoboxing/unboxing feature, however, is simply to ease the interoperability between primitive types and references without any radical changes.

Typesafe Enumerations

The int-enum will soon be gone
Like a foe we've known too long.
With type safe-enum's mighty power
Our foe will bother us no more

An enumerated type is a type whose values consist of a fixed set of constants. The C-style enumerated type, enum was omitted from the Java programming language. A commonly used pattern for enumerated types in Java is to define a class of constants as follows:

public class MainMenu {
public static final int MENU_FILE = 0;
public static final int MENU_EDIT = 1;
public static final int MENU_FORMAT = 2;
public static final int MENU_VIEW = 3;
}

This pattern has several drawbacks including:

  1. It is not type safe
  2. Constants are compiled into clients and therefore adding more constants require recompilation of the clients
  3. It has no namespace and therefore must prefix constants
  4. Provides no easy way to translate the constants into informative printable values

In addition to the above, and as we all know, an object is an instance of a class. An object has state (represented by variables) and behavior (represented by methods). The above MainMenu class has state only. So from an object-oriented point of view, it is not really a class since its instances or objects would have no behavior.

A type safe enum pattern that avoids all of the above problems has been proposed by Joshua Bloch in his book "Effective Java Programming Language Guide". The idea is to define an enum as a class that represents a single element of the enumerated type; such a class must not provide public constructors. Here is an example:

public class MainMenu {
private final String name;

private MainMenu(String name) {
this.name = name;
}

public static final MainMenu FILE = new MainMenu("file");
public static final MainMenu EDIT = new MainMenu("edit");
public static final MainMenu FORMAT = new MainMenu("format");
public static final MainMenu VIEW = new MainMenu("view");

public String toString() {
return name;
}
}

Using MainMenu, there is no way for a client to create an object of the class or extend it. This is a compile-time typesafe enumerated type: it is guaranteed that if you declare a method with a parameter of type MainMenu, then any non-null object reference passed in represents one of the four valid menu items. Any attempt to pass an incorrectly-typed object results in a compile-time error. In addition, this is a truly object-oriented class as it contains both state and behavior.

In J2SE 5.0, however, you do not need to worry about inventing your own enumeration patterns since it provides a typesafe enumerated type facility. The J2SE 5.0 enum declaration looks as follows:

public enum MainMenu {FILE, EDIT, FORMAT, VIEW};

This syntax looks much like enums in other languages such as C/C++, but in C/C++ enums are simply glorified integers where in Java a full-fledged class is generated for each enum type. This approach has many advantages including:

  1. It provides strong compile-time type safety
  2. It provides a separate namespace for each enum type and thus eliminates the need to include a prefix in each constant name
  3. Constants are not compiled into clients so you can freely add, remove, or reorder them without recompiling the clients
  4. Printed values are informative instead of just numbers
  5. Enum constants can be used wherever objects can be used

There are a couple of important things to note about enum declarations. As an example, consider the following declaration:

public enum MainMenu {FILE, EDIT, FORMAT, VIEW};

  1. The word enum is reserved and therefore if you have been using it as an identifier, you should adjust your code when compiling with a J2SE 5.0 compiler.
  2. The above enum declaration generates a class (MainMenu in the above example), which automatically implements the Comparable<MainMenu> and Serializable interfaces, and provides several members including:

    • Static variables FILE, EDIT, FORMAT, and VIEW
    • Static method values(), which is an array containing the constants in the enum
    • static method valueOf(String) that returns the appropriate enum for the string passed in
    • Appropriately overloaded equals(), hasCode, toString(), and compareTo() methods.

Here is a complete example that declares an enumeration and then prints the values:

public class Example {
public enum MainMenu {FILE, EDIT, FORMAT, VIEW}

public static void main(String[] argv) {
for (MainMenu menu : MainMenu.values())
System.out.println(menu);
}
}

And the following segment of code shows another example using the switch statement:

for(MainMenu menu : MainMenu.values()) {
switch(menu) {
case FILE:
System.out.println("FILE Menu");
break;
case EDIT:
System.out.println("EDIT Menu");
break;
case FORMAT:
System.out.println("FORMAT Menu");
break;
case VIEW:
System.out.println("VIEW Menu");
break;
}
}

It is worth noting that two classes have been added to java.util in support of enums: EnumSet (a high-performance Set implementation for enums; all members of an enum set must be of the same enum type) and EnumMap (a high-performance Map implementation for use with enum keys).

Static Imports

And from the constant interface
We shall inherit no disgrace
With static import at our side
Our joy will be unqualified

The static import feature enables you to import static members from a class or an interface and thus use them without a qualifying name. As an example, consider the following interface that contains two constant values:

package com.name;

interface XYZ {
public static final double Constant1 = someValue;
public static final double Constant2 = anotherValue;
}

Now, the constants in the XYZ interface can be used as follows:

public class MyClass implements XYZ {
....
double value = 2 * Constant1;
...
}

As you can see, a class must implement the interface in order to have access to the constants defined in the interface.

In J2SE 5.0, static import solves this problem as shown in the following example:

import static com.name.XYZ.*;

public class MyClass {
...
double value = 2 * Constant1;
...
}

As another example, consider the following static imports:

import static java.lang.Math.*;
import static java.lang.System.*;

With these two static imports, you now can use sin(x) instead of Math.sin(x), and out.println("Hello there"); instead of System.out.println("Hello there");.

Metadata

As for noble metadata
I'll have to sing its praises later
Its uses are so numerous
To give their due, I'd miss the bus

The J2SE 5.0 metadata feature is a facility that allows developers to annotate their code so that tools can generate boilerplate code (e.g stub generation to remote procedure calls) as directed by annotations. This facility allows for parsing of your Java files and generating artifacts such as XML descriptors or source code. For more information on the metadata facility, please see A Metadata Facility for the Java Programming Language.

Others

In addition to the new language constructs and features, several other enhancements have been introduced. This section provides an overview of some of the significant enhancements.

Variable Arguments:

O joyless nights, o joyless days
Our programs cluttered with arrays
With varargs here, we needn't whine;
We'll simply put the args inline

The variable arguments new functionality in J2SE 5.0 allows multiple arguments to be passed as parameters to methods as in:

void someMethod(Object ... args) {
// do something
}

// invoke the method
someMethod("arg1", "arg2", "arg3");

The notation ... is required. The printf statement, which is discussed later, is an example of using variable arguments.

Formatted Output: The variable arguments functionality has been used to implement the flexible number of arguments required for printf. That is right! J2SE 5.0 provides C-like printf functionality, so now it is possible to easily format output using printf:

System.out.printf("%s %3d", name, age);

Enhanced Input: Prior to J2SE 5.0, in order to read an integer value from the keyboard, it has to be read as a String and then parsed as follows (this code doesn't include the try and catch constructs):

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();
int n = Integer.parseInt(str);

In J2SE 5.0, the java.util.Scanner class can be used to accomplish the same thing but with less code as follows:

Scanner reader = new Scanner(System.in);
int n = reader.nextInt();

Programming educators are going to love this enhanced input functionality, as it will make it easy to explain how to read primitive data types from the keyboard.

If you need to process more complex input, use the java.util.Formatter class, which includes pattern matching algorithms.

Synchronization: J2SE 5.0 provides higher-level synchronization constructs in the form of a comprehensive library of concurrency utilities (java.util.concurrent) containing thread pools, queues, concurrent collection, special purpose locks, and barriers. This is a substantial addition that will change the way we develop concurrent Java applications. Stay tuned for an article that explains this new functionality.

Conclusion

Tiger, Tiger burning bright
Like a geek who works all night
What new-fangled bit or byte
Could ease the hacker's weary plight?

The Tiger release has introduced several new language constructs, features, and enhancements in order to further ease the development of Java applications. The code examples included in this article demonstrate how easy it is to use the new language features to improve the readability of your programs. While some of the new features, such as generics and enumerated types, do exist in other programming languages, Java has made them compile-time typesafe in order to allow you to develop safer applications with Java than with other programming languages!

Have fun with the Tiger and stay tuned for more articles that demonstrate how to use some of the more advanced features such as synchronization and metadata.

For More Information

Download J2SE 5.0
J2SE 5.0 Name and Version Change
J2SE 5.0 (Tiger) Release Contents
New Features and Enhancements in J2SE 5.0
J2SE 5.0 in a Nutshell
A Conversation with Joshua Bloch
JavaOne 2003 Technical Session 3072 (Forthcoming Java Programming Language Features)

No comments:

Post a Comment