Skip to main content

skip to main content

developerWorks  >  Java technology  >

Magic with Merlin: The generics prototype

Merlin peers into the future and sees language-level changes in Tiger

developerWorks
Document options

Document options requiring JavaScript are not displayed

Discuss


Rate this page

Help us improve this content


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.



Back to top


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.



Back to top


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.



Back to top


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.



Back to top


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);
    }
  }



Back to top


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;
        }
      }
    }
  }



Back to top


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.



Back to top


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



About the author

Author photo

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc., offers technical support through AnswerSquad.com, and is working with SavaJe Technologies to develop a next-generation mobile phone platform. His latest books are Mastering Java 2, J2SE 1.4 (Sybex, April 2002) and Learn Java with JBuilder 6 (Apress, March 2002). Reach him at jaz@zukowski.net.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top