Significant changes await the Java language: The impending August 2004 release
of J2SE 1.5—code-named “Tiger”—adds many new
key features to Java, including generics, enhanced for loops, autoboxing and
enum, static import and metadata. Some of the new features
also provide built-in language support for common idioms and patterns. In short,
Sun’s goal is to make Java code “clearer, safer, shorter and easier
to develop—without sacrificing compatibility.”
However, many observers view the new features as “syntactic sugar”—nice but nonessential window dressings. An obvious, unstated goal is to one-up the competition, and in many Java Community Process discussions (posted at www.jcp.org) you’ll find debates concerning which prominent C# features should be included in Tiger (such as operator overloading and delegates).
Whatever your initial opinion, I’ll be addressing these changes in the coming months, giving you an inside look on how this tiger is shifting its stripes. Having worked on gobs of messy, bloated code, I’m enthusiastic about the changes, which I believe will help to simplify Java development and reduce the possibility of making coding errors. However, you should be warned that some of the new features can easily be abused, leading to different kinds of problems. Also, the generics feature adds a new layer of complexity that will be difficult for the average developer to master.
Collections in Java aren’t typesafe. You can add a
String to a collection
intended to hold
Student objects, and the compiler won’t complain. Also,
the collection is oblivious to the specific type of object it contains—you
must cast to the
Student type to send
Student messages to an object extracted
from the collection. If you add
Strings to the collection, you might get a
at runtime—and deciphering
ClassCastExceptions is a pain, since code
that adds to the collection may be dispersed and distant from the code that
extracts from the collection.
In Java 1.5, you may create parameterized collections by binding the collection to a specific type:
String objects in the collection just as before, using the
If you try adding objects of any other type, the compiler will reject your code.
This is the biggest sell of generics—they offer an opportunity to
catch one more possible flaw at compile time instead of runtime.
The improvement in my mileage perhaps isn’t as great, since I now depend heavily on unit tests to catch defects. While a compiler can reduce the number of potential problems, it can’t ferret out all flaws. Extensive testing is still necessary, so I view the additional protections as nice but not essential.
When retrieving an element, you no longer need to cast:
I’m ecstatic about any elimination of casting, because it introduces the potential for runtime errors, it’s annoying and adds clutter to your code.
Multiple Type Parameters
To create a parameterized Map, you supply two type parameters: one for the key and one for the value.
When putting key-value pairs into the
Map, both the key and value must match
the corresponding parameter type. You don’t need to cast the return value
when extracting from the
Generics in the Class Library
Sun has retrofitted all collection classes and many other classes in the JDK
API to use generics. For example, you can bind the interface
Comparable to the
type being compared for sorting purposes. The
compareTo method then no longer
needs any casts:
Sun has retrofitted
Class and other reflection classes with generics.
Creating Your Own
The following declaration of the
NumList class creates a parameterized type:
You follow the class name in the class declaration with the formal parameter
list, which contains the formal type name T. My use of the identifier T is arbitrary;
I could have chosen something like
AnyNumericType instead. The
compiler replaces any appearances in the class of the naked type declaration
T with the type to which instances of
NumList are bound.
So far, you use
NumList no differently than any parameterized collection type;
you create instances of
NumList by binding it to any type.
However, you want client code to be able to only bind
to numeric wrapper types, so that you can provide a totaling mechanism. You
can specify a bounds on the formal type parameter T.
Number bounds clause means that you can bind
NumList to only
or a subclass of
Number. If you try to bind
NumList to, say,
your code won’t compile.
NumList has as its upper bounds the type
you can call any valid
Number methods on objects of naked type
T. The code for the total method in
NumList demonstrates this:
How It Works
Sun uses a scheme known as erasure that translates generics code into
classic Java byte code. A declaration of the parameterized type
is simply erased to
List. Java then replaces uses of naked types
with the upper bound, which is
java.lang.Object by default. It
also adds casts where necessary.
Versions of the pre-alpha compiler contained a javac switch
-s. This switch
let you view the Java source corresponding to the byte codes that would be generated
Note use of the
-source 1.5 switch, necessary to compile with the new features
of J2SE 1.5.
The “erased” representation of
Don’t fret—your existing Java code won’t break under the new compiler. Backward compatibility was a major consideration for J2SE 1.5. You can still use parameterized classes as raw types—without binding them to a specific type.
The upper bound still applies, however. If you try to add a non-
your code won’t compile.
When adding to raw collections, you will receive an “unchecked” warning. This means that your pre-1.5 code could potentially generate numerous warnings. Next month, I’ll cover ways to control those warnings, and delve into some of the advanced concepts that you must understand to master developing parameterized types.
Not Just Window Dressing
Trying It Out
You can download an alpha version of Tiger from http://java.sun.com, and an early-access version from July 2003 includes, for the first time ever, the complete source code for the Java compiler itself. Remember, dealing with an alpha version means that you might encounter some defects.
Other implementations of generics were proposed, but Sun chose erasure as the best route to complete backward compatibility. Stay tuned for more on this scheme’s implications—including its unfortunate limitations.
Next month: Advanced generics
Jeff Langr, owner of Langr Software Solutions, is the author of the book Essential Java Style and several articles, including two appearing in Software Development. He is currently working on a book on Java 1.5 and resides in Colorado Springs, Colo.