http://www.developer.com/

Back to article

J2SE 1.5 - Effective Java Programming with Tiger


November 21, 2003

Introduction

The forthcoming major release of Java 2 Platform, Standard Edition (J2SE) 1.5 is increasingly gaining its momentum in the developer community due to its potential improvements to the language and convincing feature set. The beta release of J2SE 1.5 is expected to ship in late 2003. J2SE 1.5, code named "Tiger," is being developed under the Java Community Process (JCP). The umbrella Java Specification Request (JSR) for this release is JSR 176. This article outlines the major features that are expected to ship with J2SE 1.5, which targets its FCS in the first half of calendar year 2004.

Component JSRs in Tiger

JSR 176 defines the release contents of Tiger. There are at least 15 component JSRs that are developed under the JCP program and targeted towards the Tiger release. Table 1 details the JSRs along with their status as of this writing.

Table 1: Tiger Component JSRs
JSR ID Description Current Status
003 Java Management Extensions (JMX) Specification Final Release 3
013 Decimal Arithmetic Enhancement Proposed Final Draft
014 Add Generic Types to the Java Programming Language Public Review
028 Java SASL Specification Maintenance Draft Review
114 JDBC Rowset Implementations Public Review 2
133 Java Memory Model and Thread Specification Revision Community Review
163 Java Platform Profiling Architecture Public Review
166 Concurrency Utilities Public Review
174 Monitoring and Management Specification for the Java Virtual Machine Public Review
175 A Metadata Facility for the Java Programming Language Community Review
199 Java Compiler API Expert Group Formation
200 Network Transfer Format for Java Archives Community Review
201 Extending the Java Programming Language with Enumerations, Autoboxing, Enhanced for Loops, and Static Import Community Review
204 Unicode Supplementary Character Support Community Review
206 Java API for XML Processing (JAXP) 1.3 Community Review

You can get the detailed information of these JSRs in the following URL: http://www.jcp.org/en/jsr/detail?id=JSR_NUMBER. Replace the JSR_NUMBER with the actual JSR ID in which you are interested. The status information mentioned in the above table is obtained from the individual JSR page in the JCP Web site.

Generics

What are generics?

Generics are also called parameterized types (often referred as type polymorphism). To make it more precise, Generics are similar to the powerful C++ templates, but remove the potential drawbacks faced by templates. Generics make type parameters explicit and type casts implicit; this is helpful in using libraries in a safer and flexible manner. One good example could be the collections library.

Generics support in Java is the language feature most frequently requested by the Java developers. This feature has been postponed for quite some time because it requires changes to the Java Language Specification, and also updates to the Java Virtual Machine (JVM) Specification. Finally, this feature stands as the top priority for the Tiger release.

Generics types

There are two forms of generics types:

  1. Parameterized types
  2. Type variables

A parameterized type consists of a class or interface type C and a parameter section <T1,. . .,Tn>. C must be the name of a parameterized class or interface, the types in the parameter list <T1,. . .,Tn> must match the number of declared parameters of C, and each actual parameter must be a subtype of the formal parameter's bound types.

A type variable is an unqualified identifier. Type variables are introduced by parameterized class and interface declarations and polymorphic method declarations [For simplicity, these definitions are borrowed from section 2.1 of "Adding Generics to the Java Programming Language: Participant Draft Specification dated April 27, 2001."]

The generics syntax allows developers to enforce parameters that extend a Class or implement an interface. This helps in restricting the type of parameters for a generic class/interface/method and they are referred to have bound types. Listing 2 details the usage of generics in parameterized types, classes, interfaces, and methods.

Parameterized Type Example

List<Integer> integerList       = new LinkedList<Integer>()
Map<String, Integer> integerMap = new HashMap<String, Integer>()
Stack<Integer> integerStack     = new Stack<Integer>()

Generic Class Example

public class C<T1, T2> {
  private T1 type1;
  private T2 type2;
  public C(T1 type1, T2 type2) {
    this.type1 = type1;
    this.type2 = type2;
  }
  public T1 getType1() {
    return this.type1;
  }
  public T2 getType2() {
    return this.type2;
  }

  public static void main(String args[]) {
    C<String, Integer> cStrInt = new C<String, Integer>("one", 1);
    String type1StrInt = cStrInt.getType1();
    Integer type2SI    = cStrInt.getType2();

    C<Integer, Boolean> cIntBool = new C<Integer, Boolean>(1, true);
    Integer type1IntStr = cIntBool.getType1();
    Boolean type2IntStr = cIntBool.getType2();
  }
}

Generic Interface Example

public interface I<T> {
  public T getConnectionPool();
  public void releaseConnectionPool(T connectionPool);
}

Generic Method Example

public class M {
  public static <T extends Comparable> T minimum(T a, T b) {
    if(a.compareTo(b) <= 0) return a;
      else return b;
  }
  public static void main(String[] args) {
    Integer b1  = new Integer(2);
    Integer b2  = new Integer(5);
    Integer min = minimum(b1, b2);
    System.out.println("Minimum of (2,5) : " + min);
  }
}

Listing 2: Generics usage in parameterized types, classes, interfaces and methods.

Generics Advantage

Listing 3 shows the usage of generics in collection libraries. When using generics, you need to define the type the collection can hold. This helps the collection maintain homogeneous objects. If an undefined type is added to this collection, you will be notified of errors at compile time. This helps us to identify the cause of the problem during the development time.

On the contrary, the traditional way of using heterogeneous objects in a collection may result in runtime errors. Sometimes, these errors, which are very crucial to the product's quality, are uncovered during deployment time.

With Generics

Map<Integer> map = new HashMap<Integer>();
map.put("one", new Integer(1));
Integer integer = map.values().iterator().next();

Without Generics

Map map = new HashMap();
map.put("one", new Integer(1));
Integer integer = (Integer)map.values().iterator().next();

Listing 3: Generics usage in a collection.

Thus, the generics approach is more readable and yet powerful than the traditional approach.

Collection Filtering

Filtering a collection is prone to ClassCastException when the collection elements are heterogeneous. This may fail at runtime due to invalid casts. This behaviour is overcome with the use of generics in collection filtering. This helps developers detect the errors at compile time.

Listing 4 shows the collection filtering today and filtering collection with generics.

import java.util.*;
public class CollectionFiltering {

  /*
   * Traditionally, collections are allowed to hold heterogeneous
       * elements. This causes run-time error due to poor type
       * checking. These errors are uncovered only during testing
       * or deployment time, which are very crucial to the success
       * of the product.
   */
  static void purgeFromCollection(Collection c) {
    for (Iterator i = c.iterator(); i.hasNext(); ) {
      String s = (String) i.next();
      if(s.length() == 4)
        i.remove();
    }
  }
  /*
   * Generics restricts the collection to hold homogeneous
   * elements. When an element other than String is added to this
   * collection, this causes compile-time error. Generics helps us
   * in preventing the run-time exceptions.
   */
  static void purgeFromGenerics(Collection<String> c) {
    for (Iterator<String> i = c.iterator(); i.hasNext(); ) {
      if(i.next().length() == 4)
        i.remove();
    }
  }
  public static void main(String args[]) {
      //switch between approaches for behaviour.
    //List<String> arrayList = new
                   ArrayList<String>();    //generics approach
    List arrayList = new ArrayList();      //traditional approach
    arrayList.add(new Integer(0));
    arrayList.add(new String("1"));
    arrayList.add(new String("2"));
    purgeFromCollection(arrayList);
  }
}

Listing 4: Collection filtering with generics.

Getting Started with Generics

Download the 2.2 early access release of the generics prototype from http://developer.java.sun.com/developer/earlyAccess/adding_generics/. This distribution contains a prototype implementation for JSR14 and JSR 201 language features. This release now requires JDK 1.4.2 bootstrap VM.

collect.jar contains stubs for generics collection classes for compiling against rt.jar.

gjc-rt.jar contains generic compiler as well as a number of modified platform classes. This file should be placed on your VM's bootstrap classpath when compiling and running code developed for use with this prototype.

Extract this distribution to a folder. Set the following environment variables for compiling and running generics code.

SET J2SE14=PATH_TO_J2SE1.4.x_INSTALL_DIR

For example in Windows 2000,

SET J2SE14=C:\j2sdk1.4.2

SET JSR14DISTR=PATH_TO_PROTOTYPE_DIR

For example, in Windows 2000,

SET JSR14DISTR=C:\adding_generics-2_2-ea

Use the scripts (javac.bat & java.bat) provided in the "%JSR14DISTR%\scripts" directory to compile and run the code used in this article.

Tools that Support Generics

Tools and IDEs are available for writing generics enabled code today. Some of them are listed below.

Clover 1.1.1
http://www.thecortex.net/clover/generics.html

DrJava
http://drjava.sourceforge.net/

IntelliJ IDEA 4.0
http://www.intellij.com/idea/features4

Typesafe Enumerations

What is enum?

Enum is a special kind of class declaration. A typesafe enum facility defines a fixed set of constant legal values for types. This feature is borrowed from the C language and has been incorporated into the Java language in the Tiger release.

Advantages of enum

The proposed enum facility has more advantages when compared with the traditional int enum approach in Java. The advantages are outlined below.

  • enum provides compile time type safety
  • enum provides proper name spacing for its types
  • Performance comparable to int constants
  • Typesafe constants do not require a compilation when clients modify constants
  • Printed values are informative
  • enum can be used in collections because they are objects
  • enum is a special kind of class declaration; hence, one can add arbitrary fields and methods
  • enum can be made to implement arbitrary interfaces

Traditional enum pattern

Listing 5 shows the commonly used pattern for enumerated types in Java that suffer from many drawbacks. In this approach, whenever you modify the client code, you need to recompile.

public class Continent {
   public static final int CONTINENT_AFRICA          = 0;
   public static final int CONTINENT _ASIA           = 1;
   public static final int CONTINENT _EUROPE         = 2;
   public static final int CONTINENT_NORTH_AMERICA   = 3;
   public static final int CONTINENT_OCEANIA         = 4;
   public static final int CONTINENT_SOUTH_AMERICA   = 5;
}

Listing 5: enum pattern with fallbacks.

Typesafe enum pattern

Java provides an alternative method to overcome the drawbacks of the traditional approach. This is called the typesafe enum pattern. This pattern defines a class that represents a single element of an enumerated type that doesn't provide any public constructors to it. For each constant in the enumerated type, provide static final fields. Listing 6 shows this pattern approach. This pattern provides compile time type safety by allowing that only any of the six continents defined can be passed to a method which defines a parameter of type Continent.

public class Continent {
    private final String name;

    private Continent(String name) { this.name = name; }

    public String toString()  { return name; }

    public static final Continent AFRICA =
        new Continent ("africa ");
    public static final Continent ASIA =
        new Continent ("asia");
    public static final Continent EUROPE  =
        new Continent ("europe");
    public static final Continent NORTH_AMERICA =
        new Continent ("north america");
    public static final Continent OCEANIA =
        new Continent ("oceania");
    public static final Continent SOUTH_AMERICA =
        new Continent ("south america");
}

Listing 6: The typesafe enum pattern.

Proposed enum facility

The proposed facility is simple and readable. The construct can be used with switch statements. Listing 7 shows the usage of the proposed enum facility for the Java language.

public class EnumFacility {
    enum Continent { africa , asia, europe, north_america, oceania,
                     south_america };
  public static void main(String args[]) {
    System.out.println("Continents are : " + Continent.VALUES);
    for ( Continent c : Continent.VALUES ) {
      // switch on enum
      switch(c) {
        case Continent.africa:
        System.out.println("in africa.");
        break;
        case Continent.asia:
        System.out.println("in asia.");
        break;
        case Continent.europe:
        System.out.println("in europe.");
        break;
        case Continent.north_america:
        System.out.println("in north_america.");
        break;
        case Continent.oceania:
        System.out.println("in oceania.");
        break;
        case Continent.south_america:
        System.out.println("in south_america.");
        break;
      }
    }
  }
}

Listing 7: Proposed typesafe enum facility.

Autoboxing

What is autoboxing?

Developers are burdened when they convert primitive types to wrapper (reference) types (for example, converting int to Integer type). Adding primitive types to a collection is not possible unless they are converted to the corresponding reference type. To overcome this drawback of the current type system, the need for automatic conversion of primitive type data to their corresponding wrapper type data was proposed. This conversion mechanism is known as autoboxing.

Listing 8 illustrates the code that achieves autoboxing in a collection. In this code sample, the primitive type int is added to a collection that holds an Integer reference. The compiler takes care of the type conversion for you.

import java.util.*;

public class AutoBoxing {
  static List<Integer> testAutoBoxing(int ii) {
    int i = 0;
    List<Integer> arrayList = new ArrayList<Integer>();
    arrayList.add(++i);
    arrayList.add(new Integer(11));
    arrayList.add(++ii);
    return arrayList;
  }
  public static void main(String args[]) {
    List<Integer> arrayList = testAutoBoxing(110);
    for (Integer i : arrayList)
      System.out.println(i);
  }
}

Listing 8: Autoboxing in a Collection.

There are several other forms of conversion that are supported by the compiler. Refer to JSR201 for more information: http://jcp.org/aboutJava/communityprocess/jsr/tiger/autoboxing.html.

Enhanced for Statement

What is wrong with the current for statement?

The current for statement is very efficient and powerful in all aspects. But, it is not optimized when it iterates over a collection because the iterators are used only for getting elements out of a collection and serve no other purpose. Generics helped make this situation better by adding the type safety to the collection. This resulted in proposing "enhanced for" statements with generics additions to it. With this new feature, the compiler takes care of the iterator for you. Listing 9 details the usage of "enhanced for" statements.

import java.util.*;

public class TestForStatements {

  static StringBuffer buffer = null;
  public static void testCurrentForStatements(Collection c) {
    buffer = new StringBuffer();
    for (Iterator i = c.iterator(); i.hasNext(); ) {
      String s = (String) i.next();
      buffer.append(s+"\n");
    }
    System.out.println("Collection elements from traditional for
                        statement : \n" + buffer.toString());
  }
    public static void testEnhancedForStatements(Collection<String>
                                                 c) {
    buffer = new StringBuffer();
    for (String s : c) {
      buffer.append(s+"\n");
    }
    System.out.println("Collection elements from enhanced for
                        statement : \n" + buffer.toString());
  }
  public static void main(String args[]) {
    List featureList = new ArrayList();
    featureList.add("Java java = new Java();");
    featureList.add("java.addFeature(\"generics\");");
    featureList.add("java.addFeature(\"enum facility\");");
    featureList.add("java.addFeature(\"enhanced for\");");
    featureList.add("java.addFeature(\"auto boxing\");");
    featureList.add("java.addFeature(\"static import\");");
    featureList.add("Tiger.commitFeatureSet(java);");
    testCurrentForStatements(featureList);
    testEnhancedForStatements(featureList);
  }
}

Listing 9: "enhanced for" statements usage in a collection.

Using the "enhanced for" statement in an int array

The "enhanced for loop" has been specifically designed for iteration over collections and arrays. Its usage in an integer array is shown in Listing 10.

public class TestIntegerArrayUsingEnhancedForLoop {
  public static void main(String args[]) {
    int [] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int sum = 0;
    for (int e : a)
      sum += e;
    System.out.println("Array Sum : " + sum);
  }
}

Listing 10: "enhanced for" statements usage in an integer array.

Static Import

Rationale for static import

In the Java world, when using any mathematical functions from the "java.lang.Math" package or when using named constants, one has to prefix the method name or field name with the class name. This way of coding looks more verbose. To provide convenience to the developers, the concept of a static import was proposed. By using this, one can allow the import of static methods and fields similar to classes and interfaces.

import static java.lang.StrictMath.*; // import static
import static java.lang.System.*; // import static

public class StaticImport {
  static void testStaticImport() {
    out.println("The square root of PI is : " + sqrt(PI));
  }
  public static void main(String args[]) {
    testStaticImport();
  }
}

Listing 11: Usage of static import.

In Listing 11, the usage of static import is illustrated. The traditional approach is discussed below.

When accessing a static method, you need to prefix with the class name. For example,

  Math.sqrt(Math.PI);
  StrictMath.IEEEremainder(4.0, 2.0);
System.out.println("hello");

When accessing named constants, you need to prefix with the class name. For example,

  Math.PI

This approach makes code more verbose. The static import helps overcome this approach. This is a simple feature, but yet a convincing one for developers.

Conclusion

The features that were discussed in this article are only a subset of features that are planned to ship with Tiger. These features are developer savvy and yet powerful additions to the Java Programming language. Most of the listings in this article are tested with the Generics early access compiler version 2.2. Although enough features are targeted towards the Tiger release, the final specification will become soon available for review once the component JSRs releases them.

References

JSR 176-J2SETM 1.5 (Tiger) Release Contents
http://www.jcp.org/en/jsr/detail?id=176

JSR 14-Add Generic Types To The JavaTM Programming Language
http://www.jcp.org/en/jsr/detail?id=014

JSR 201-Extending the JavaTM Programming Language with Enumerations, Autoboxing, Enhanced for loops and Static Import
http://www.jcp.org/en/jsr/detail?id=201

Generics Prototype for JSR014
http://developer.java.sun.com/developer/earlyAccess/adding_generics/ (you must be a registered member of the Java Developer Connection)

GJ: A Generic Java Language Extension
http://www.research.avayalabs.com/user/wadler/gj/

About the Author

Arulazi Dhesiaseelan has been working as a Senior Software Engineer for the Hewlett-Packard Company, India. He has a Master of Computer Applications degree from PSG College of Technology, India. He has more than three years of industry experience. He was also involved in the UDDI4J project hosted at http://uddi4j.org. He has been working on Web Service related technologies such as WSDL, UDDI, and SOAP. Currently, he is involved in developing an object-based infrastructure for mobile solutions. He can be reached at aruld@acm.org.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date