Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Preparing for Generics

 
 

Articles Index


Generics -- also commonly known as parameterized types -- have been used in other computing languages for years. And now, due to popular demand, generics is slated to be added to the Java language with the 1.5 release.

The Problem with Lists

With generics, types that contain data (such as lists) are not defined to operate over a specific type of data; instead, they operate over a homogeneous set, where the set type is defined at declaration. How exactly does that help the Java developer?

The best way to understand what generics can do for you is to study some Java code that would benefit from generics. The sample below, written to the current Java language specification, contains a list of String object elements and a list of Integer object elements (not the primitive type). Because both elements are subclasses of the Object class, and Java has polymorphic references, you can apply the list's methods to both objects. Unfortunately, as far as the compiler is concerned, the elements in both lists are of the type Object, so the only way to differentiate between the two lists is to use runtime type discrimination on the elements. Even worse, if a developer confuses the two lists and performs an illegal cast on an element, the error is not caught until runtime.

Below are some examples of such errors. In the first example (lines 13 to 20), you might believe you're working with a list of Integer objects, when in reality it's a list of Strings. In the second example (lines 11 and 22 to 27), you might think you're working with a homogenous set of String, but this is a heterogeneous set of both String and Integer elements. So unless you create a new list subclass for every element type (which would undermine the advantages of OO reuse), there's no way to statically constrain the list to a set of homogeneous elements. And in this simple example, the errors are fairly easy to catch. In a bigger program, you'd have even bigger problems.


  1..
  2.  List stringList  = new LinkedList();
  3.  List integerList = new LinkedList();
  4.
  5.  integerList.add(new Integer(1));
  6.  integerList.add(new Integer(2));
  7.
  8.  stringList.add(new String("I am a String"));
  9.
  10. // Nothing constrains the elements to a homogeneous set.
  11. stringList.add(new Integer(1));
  12.
  13. Iterator listIterator = integerList.iterator();
  14.
  15. // Compiler unaware of the list's return type and the illegal cast.
  16. // Developer meant to iterate through the string list.
  17. while(listIterator.hasNext()) {
  18.
  19.   // Illegal cast caught at runtime.
  20.   String item = (String)listIterator.next();
  21. }
  22.
  23. listIterator = stringList.iterator();
  24. // No guarantee of homogeneous containers.
  25. while (listIterator.hasNext()) {
  26.   // fail at runtime due to heterogeneous set
  27.   String item = (String)listIterator.next();
  28. }
  29..

The Generics Advantage

With generics, you achieve polymorphic behavior similar to the example above, but with strong static type-checking; the compiler knows that the two lists are different because they contain different elements, and these lists are guaranteed to contain only a homogeneous set of elements. The sample code below is a translation of the previous example, using generics this time. As you can see from comments in the code, all the errors are caught at compile time. Don't worry about the syntax for now -- we'll cover that shortly.

In comparing the two examples, you should notice that additional type information is included in the generics code, which directs the compiler as to what type each container should contain.


  1..
  2.  import java.util.LinkedList;
  3.  import java.util.Collections;
  4.  import java.util.Iterator;
  5.
  6.  public class genericsExample2{
  7.
  8.  static public void main(String[] args) {
  9.     LinkedList<String>  stringList  = new LinkedList<String>();
  10.    LinkedList<Integer> integerList = new LinkedList<Integer>();
  11.
  12.    integerList.add(new Integer(1));
  13.    integerList.add(new Integer(2));
  14.
  15.    stringList.add(new String("I am a String"));
  16.    stringList.add(new Integer(1)); // causes a compilation error
  17.
  18.    /* genericsExample2.java:16: cannot resolve symbol
  19.    ** symbol : method add (java.lang.Integer)
  20.    */
  21.
  22.    Iterator<Integer> listIterator = integerList.iterator();
  23.    String item;
  24.    while(listIterator.hasNext()) {
  25.       item = listIterator.next(); // causes a compilation error
  26.      
  27.       /* genericsExample2.java:25: incompatible types
  28.       ** found : java.lang.Integer
  29.       ** required: java.lang.String
  30.       */
  31.    }
  32.
  33.    listIterator = stringList.iterator(); // causes a compilation error
  34.
  35.    /* genericsExample2.java:33: incompatible types
  36.    ** found : java.util.Iterator<java.lang.String>
  37.    ** required: java.util.Iterator<java.lang.Integer>
  38.    */
  39.    // the iterator is guaranteed to be homogeneous
  40.    while (listIterator.hasNext()) {
  41.      item = listIterator.next();
  42.
  43.      /* genericsEx2.java:41: incompatible types
  44.      ** found : java.lang.Integer
  45.      ** required: java.lang.String
  46.      */
  47.    }
  48. } // main
  49. } // class genericsExample2

With these examples, you can understand why generics is among the most-requested additions to the Java language. Here are a few of the benefits:

  • The flexibility of dynamic binding, with the advantage of static type-checking. Compiler-detected errors are less expensive to repair than those detected at runtime.
  • There is less ambiguity between containers, so code reviews are simpler.
  • Using fewer casts makes code cleaner.

Basic Syntax Overview

So far, you've only seen the genericized container classes provided to us. But you can also declare your own generic interfaces, classes, and methods. The following table illustrates the syntax you would use.

 

Syntax

Paramaterized Type Vector<String> stringVector = new Vector<String>
List<Integer> integerList = new List<Integer>
Interface interface List<Element> implements MyInterface{...}
Class class MyList<Element> {...}
class MyList<Element> implements List<Element> {...}
Method boolean containsBoth(Element a, Element b);
static <Element> boolean swap(List<Element> list, int i, int j);

The following example uses similar syntax in code: MyInterface

Getting Started with Generics

For more information on generics, you can refer to the specification and to the JSR 14. Developers can start writing generics code today using a prototype implementation of the Java compiler, which supports generics (as described in the draft specification). The prototype includes: the source written in the extended language, a jar file containing the class files for running and bootstrapping the compiler, and a jar file containing stubs for the collection classes. It also includes a Java source example and a helpful makefile that compiles the source and invokes the Java Virtual Machine (JVM). Here are the steps to get started using C-shell.

  1. Download the generics prototype archive file
    If you are not already a member of the Java Developer Connection, you will need to register.
    Unzip the archive into the installation directory /install_dir
    - unzip adding_generics-1_3-ea.zip

  2. Download and install JDK 1.4.1

  3. Set the environment variables

    setenv JSR14DISTR /install_dir/jsr14_adding_generics-1_3-ea
    setenv J2SE14 /jdk_install_dir

  4. Run the examples

    cd /install_dir/jsr14_adding_generics-1_3-ea/examples
    Compile and run the Test.java sample using the makefile.
    - make

See Also

About the Author

Paul Mingardi is a Market Development Engineer at Sun Microsystems, working on technology adoption for partners in health care, banking, and finance. He also works with independent software vendors, to help them become successful using Java and other Sun technologies. Paul is a Sun Certified Enterprise Architect and holds a total of seven certifications.

Oracle is reviewing the Sun product roadmap and will provide guidance to customers in accordance with Oracle's standard product communication policies. Any resulting features and timing of release of such features as determined by Oracle's review of roadmaps, are at the sole discretion of Oracle. All product roadmap information, whether communicated by Sun Microsystems or by Oracle, does not represent a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. It is intended for information purposes only, and may not be incorporated into any contract.