Tiger Stripes



March 01, 2004
URL:http://www.drdobbs.com/tiger-stripes/184415111

Tiger Stripes

Software Development

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 varags, typesafe 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.

Generics

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 ClassCastException 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:

You store String objects in the collection just as before, using the add method. 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 Map.

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 ThreadLocal, 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 NumList to numeric wrapper types, so that you can provide a totaling mechanism. You can specify a bounds on the formal type parameter T.

The extends Number bounds clause means that you can bind NumList to only Number or a subclass of Number. If you try to bind NumList to, say, java.util.Date, your code won’t compile.

Since NumList has as its upper bounds the type Number, 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 List<Student> 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 by compilation:

Note use of the -source 1.5 switch, necessary to compile with the new features of J2SE 1.5.

The “erased” representation of NumList:


Raw Types

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-Number instance, 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.

—J. Langr

The addition of generics to Java is significant—far more than just syntactic sugar—and will alter the fundamental look of Java code. I’m satisfied with the impact to the average developer who might use the parameterized types provided as part of the collections framework, but developing parameterized types requires a solid understanding of the erasure scheme. I’d categorize the appropriate knowledge as approaching advanced skill level.

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.

Terms of Service | Privacy Statement | Copyright © 2024 UBM Tech, All rights reserved.