Tuesday, April 29, 2008

How to use generics

The 5.0 release of J2SE includes the first set of significant language-level changes to the Java platform in some time. In addition to new constructs for things such as the enhance for loop and variable argument lists, J2SE 5.0 provides compile-time type safety with the Java Collections framework through generics in accordance with JSR-14: Add Generic Types To The Java Programming Language.

One of the primary uses of generics is to abstract data types when working with collections. Prior to the JDK 5.0 release, when you created a Collection, you could put anything in it, for example:

List myList = new ArrayList(10);
myList.add(new Integer(10));
myList.add("Hello, World");

If you wanted to restrict your Collection to a specific type, it was difficult at best. Getting items out of the collection required you to use a casting operation:

Integer myInt = (Integer)myList.iterator().next();

If you accidently cast the wrong type, the program would successfully compile, but an exception would be thrown at runtime. Unless you dealt specifically with everything in the Collection as an Object, casting typically happened blindly -- or by doing an instanceof check before calling the casted operation.

Iterator listItor = myList.iterator();
Object myObject = listItor.next();
Integer myInt = null;
if (myObject instanceof Integer) {
myInt = (Integer)myObject;
}

That situation underscores the beauty of generics. Generics allows you to specify, at compile-time, the types of objects you want to store in a Collection. Then when you add and get items from the list, the list already knows what types of objects are supposed to be acted on. So you don't need to cast anything. The "<>" characters are used to designate what type is to be stored. If the wrong type of data is provided, a compile-time exception is thrown. For example, if you try to compile the following class:

import java.util.*;

public class First {
public static void main(String args[]) {
List myList = new ArrayList(10);
myList.add(10);
myList.add("Hello, World");
}
}

you get an error like this:

   First.java:7: cannot find symbol
symbol : method add(java.lang.String)
location: interface java.util.List
myList.add("Hello, World");
^
1 error


Here's the old way of looping through a List of String objects, that is, without generics and an enhanced for loop:

import java.util.*;

public class Old {
public static void main(String args[]) {
List list = Arrays.asList(args);
Iterator itor = list.iterator();
while (itor.hasNext()) {
String element = (String)itor.next();
System.out.println(element + " / " + element.length());
}
}
}

If you compile and run the Old class and then run it with a string, like this:

   java Old Hello

you get:

   Hello / 5

With JDK 5.0, you can combine the new enhanced for loop construct with generics to create a program that is type-safe at compile-time, and is more readable and more maintainable. Here's what looping through a List of String objects looks like if you use generics and an enhanced for loop:

import java.util.*;

public class New {
public static void main(String args[]) {
List list = Arrays.asList(args);
for (String element : list) {
System.out.println(element + " / " + element.length());
}
}
}
   java New Hello
Hello / 5

As demonstrated here, generics and the enhanced for loop work well together.

For more information on generics, see:

  1. Tutorial: Generics in the Java Programming Language (pdf)
  2. JSR-14: Add Generic Types To The Java Programming Language
  3. Generics

Copyright (c) 2004-2005 Sun Microsystems, Inc.
All Rights Reserved.



For more details: Java Tips

No comments: