 | Level: Introductory John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.
19 Dec 2003 J2SE 1.5 (a.k.a. Tiger) hasn't yet made its official debut, but you can take the early access release of the generics prototype download out for a spin now. Try out parameterized types, enumerations, variable argument
lists, autoboxing, enhanced for loops, and static imports -- all language-level enhancements expected in the 1.5 release of J2SE. Share your thoughts on this article with the author and other readers in the accompanying discussion forum. (You can also click Discuss at the top or bottom of the article to access the forum.)
The forthcoming beta release of Tiger, version 1.5 of J2SE scheduled for the first half of 2004, includes several language-level changes to the Java platform. With the exception of the addition of some minor new keywords like strictfp and assertions, the Java programming language itself hasn't changed much since the addition of
inner classes back in version 1.1. This next version of the standard edition is expected to have a number of significant changes. Assuming Java Specification Requests (JSRs) 14 and 201 make their way into JSR 176 (the Tiger release), you'll find support for parameterized data types (also called generics), system-supported enumerations, autoboxing, enhanced for loops, and static imports. Let's explore the early access to these features Sun provides in a prototype.
Installing the prototype
The Sun Developer Network contains version 2.2 of a prototype for support for adding generics. While the feature isn't expected until version 1.5, the prototype works with the 1.4.2 release. The prototype also includes support for the previously mentioned language constructs, so you can experiment with the features until version 1.5 becomes available.
To get the generics prototype, visit the Sun Developer Network link in the Resources section. After downloading, you'll need to unpack it and make sure some environment variables are set. Essentially, some Java Archive Files (JARs) in the download need to replace standard system classes with newer versions of the classes. Without them, the prototype package is unusable.
The two environment variables you'll need to set are JSR14DISTR to the location where you unpacked adding_generics-2_2-ea.zip and J2SE14 to where your J2SDK 1.4.2 installation is. Listing 1 shows one possible setting on a Microsoft Windows platform (your locations may be different):
Listing 1. Environment variable setup
set JSR14DISTR=c:\adding_generics-2_2-ea
set J2SE14=c:\j2sdk1.4.2
|
To see if your configuration is correct, there is a Test.java source example in the examples subdirectory that comes with the prototype. You'll need to compile it with the javac script found in the scripts subdirectory. If it compiles correctly, your environment is configured fine. If not, be sure your environment variables are set correctly.
Once you've configured your environment correctly, you can move on to explore the new language changes.
Using generics
We've used a few terms that you might not be familiar with yet, the first of which are generics and parameterized types (often referred to as templates). Essentially, support for generics allows you to have type-safe collections, with more explicit compile-time checks and less explicit casting. Generics are much more involved than that, but one key benefit is that you can now say that you want a List of objects of type String. If you then try to put an Integer into the List, it will reject the attempt at compile time. Also, when you fetch elements out of the List, you don't have to explicitly cast them back to a String. That is done automatically. The exact syntax of this feature could change, but in its simplest case, you just add <type> around the declarations for the collections, where type is the specific datatype you want to store in the collection.
Listing 2 shows how to convert the array of command-line arguments passed into the main() method into a List of String objects:
Listing 2. Trying out generics
import java.util.*;
public class StringList {
public static void main (String args[]) {
// Create a List of type String
List<String> listOne = Arrays.asList(args);
// Make editable copy of List of type String
List<String> listTwo = new ArrayList<String>(listOne);
// Print contents
System.out.println(listTwo);
// Fetch element
String head = listTwo.get(0);
// Print element
System.out.println(head);
// Add item to list
listTwo.add(head);
// Print contents
System.out.println(listTwo);
// Can't do item of type List.
// Won't compile.
/* listTwo.add(listOne); */
}
}
|
After you compile the program with the special javac script, run it with the special java script. Pass in a set of command-line arguments to show that they are placed into the List as String objects and a single item is retrieved out of the list and added back. The last line of the main() method is commented out because it won't compile.
Because listTwo was declared to be of type String, the compiler will prevent you from trying to add an element of type List to it.
Working with system-supported enumerations
Enumerations are language constructs that allow you to define a set of related constant values. The values are then used when you need to represent one of those constants. For example, the Boolean class has constants for TRUE and FALSE. These are the complete set of values
that can be of type Boolean. Because the datatype of TRUE and FALSE are of type Boolean, the compiler can check if they are the
proper type. On the other hand, the java.awt.event.ComponentEvent class has a set of
static integers defined for the class -- for instance, COMPONENT_MOVED. These integers are passed into the ComponentEvent constructor as an int. It is then the responsibility of the constructor to verify that the range of integers passed in is valid. Of course, because the
constructor will accept any int element, if you happen to know that COMPONENT_MOVED is 100, there is no way for the compiler to tell the difference between 100 and the constant.
Therein lies the problem. While you can certainly create enumerations yourself (like with Boolean), if not done correctly, you'll have problems. And to do so correctly requires a lot of code for a simple task. (See the Resources section for some past attempts.)
JSR 201 proposes to add a new enum keyword, in which the enumeration would be named and the set of possible values would then go within braces, as in enum Color {red, green, blue}. You could then access the values like any other, as in Color.green, and use them in a switch statement. Listing 3 demonstrates the use of enum:
Listing 3. Trying out enumerations
public class EnumTest {
public static void main(String args[]) {
enum Color {red, green, blue};
// Get collection of values
System.out.println(Color.VALUES);
// Check if collection type is java.util.List
System.out.println(Color.VALUES instanceof java.util.List);
// Create variable of type
Color aColor = Color.green;
// Use enumeration in switch
switch(aColor) {
case Color.red:
System.out.println("Got red.");
break;
case Color.green:
System.out.println("Got green.");
break;
case Color.blue:
System.out.println("Got blue.");
break;
}
}
}
|
In addition to defining and using an enumeration, the example demonstrates the use of a newly defined variable of the
enumeration VALUES. This returns a List with all the enumerated elements in it.
Having variable argument lists
Another new feature expected to be in Tiger is support for variable argument lists. Previously, if you required support of a variable number of arguments, you passed in an array of objects (Object[ ]) and then asked for its length. Now, by specifying a ... in the argument list, you essentially get the same thing. Listing 4 shows what the method declaration and calling might look like. We'll save a full demonstration
until we review the enhanced for loop capabilities.
Listing 4. Trying out variable argument lists
public static void printf(String fmt, Object... args) {
// ...
}
printf("Hello, %\n", first);
printf("Hello, % %\n", first, last);
printf("Hello, % (%) %\n", first, middle, last);
|
You access args through an array access, as in args[0]. This is really no different from the old way of using variable arguments; it just looks different. It wouldn't surprise me if this feature was cut from the final Tiger release.
Handling autoboxing
Autoboxing is the automatic conversion from a primitive type to its Object equivalent, or vice versa, on method calls. For instance, if calling a method requires an Integer and you
call it with an int, the compiler will do the necessary conversion for you to ensure the proper type is passed into the method. This doesn't happen with assignments. Listing 5 demonstrates this feature:
Listing 5. Trying out autoboxing
public class BoxingTest {
public static void main(String args[]) {
test1(1);
test2(new Integer(2));
}
private static void test1(Integer i) {
System.out.println("test1: " + i);
}
private static void test2(int i) {
System.out.println("test2: " + i);
}
}
|
Exploring enhanced for loops
Besides generics, the most interesting new feature in Tiger is the enhancements to the for loop, which no longer requires that you have two semicolons within the for loop construct to give the pre and post conditions with the test. Instead, using just a colon, you get a for-each construct that will loop for each element in an array or Collection. Listing 6 demonstrates this feature with the definition of the printf() method for the array and the looping through the VALUES of the Color for the Collection:
Listing 6. Trying out enhanced for loops
public class ForEach {
enum Color { red, green, blue };
public static void printf(String fmt, Object... args) {
int i = 0;
for (char c : fmt.toCharArray()) {
if (c == '%') {
System.out.print(args[i++]);
} else if (c == '\n') {
System.out.println();
} else {
System.out.print(c);
}
}
}
public static void main(String args[]) {
printf("Addition: % plus % equals %\n", 1, 1, 2);
printf("Colors are %\n", Color.VALUES);
for (Color aColor : Color.VALUES) {
switch(aColor) {
case Color.red:
System.out.println("Got red.");
break;
case Color.green:
System.out.println("Got green.");
break;
case Color.blue:
System.out.println("Got blue.");
break;
}
}
}
}
|
Including static imports
The last of the language-level features is the static import. By adding the word static after the import keyword, you change your import to a static one. What does that self-referential definition mean? Well, when an import is static, all the accessible methods and variables of the class can be used without prefixing its access with the class name. For instance, if you static import the java.awt.Color class with import static java.awt.Color.*;, you just have to include RED in your code, instead of Color.RED. Listing 7 shows a simple version of this feature:
Listing 7. Trying out static imports
import static java.awt.Color.*;
public class ImportTest {
public static void main(String args[]) {
System.out.println(RED);
}
}
|
One reason for this addition is to avoid unnecessary implementations of interfaces that were just created to define constants for a class.
Conclusion
We're all eagerly awaiting the first public beta release of Tiger. But until Sun makes it available, the generics prototype download will at least enable you to play around with the early access versions of the language-level features. Sun is eager to get feedback on the changes, so try it out then send your comments to jsr14-prototype-comments@sun.com.
Resources - Participate in the discussion forum.
- Check out John Zukowski's complete collection of Magic with Merlin tips.
- Download the generics prototype from the Sun Developer Network.
- Get the details on adding generic types to the Java programming language in JSR 14.
- Explore JSR 201 with the generics prototype download. It adds enumerations, autoboxing, enhanced
for loops, and static imports to the Java programming language.
- Read JSR 176 for an update on the progress of Tiger.
- Check out the Pizza language extension; an early version of its generics support morphed into JSR 14.
- Explore PolyJ, another early attempt at parameterized types with the Java programming language.
- JavaWorld first examined how to "Create enumerated constants in Java" back in 1997.
- Sun's Tech Tips demonstrated using enumerations in 2001.
- Go here to see why, if not done correctly, custom typesafe enumerations aren't safe.
- Examine an early proposal for catching more errors at compile time with Generic Java (developerWorks, March 2001).
- Learn about the basics of the Java programming language in this jGuru tutorial.
- Check out "Diagnosing Java code: The case for static types" (developerWorks, June 2002) by Eric Allen to see how static types can make your code more robust.
- In "Improve modularity with aspect-oriented programming" (developerWorks, January 2002), Nicholas Lesiecki shows you how to add Aspect-oriented programming to the Java language and improve modularity with even more additions to the Java programming language.
- IBM Research is also focusing on subject-oriented programming, which offers subjects -- collections of classes or class fragments that have a unique "view" of a system. Subjects are composed into applications with composition rules.
- You'll find hundreds of articles about every aspect of Java programming in
the IBM developerWorks Java technology zone.
About the author
Rate this page
|  |