madbean

Exploring the syntax in the JDK1.5 early access compiler

07 Oct 2003

This is attempt to document the syntax available in the current JDK1.5 early access compiler (2_2-ea). The exact syntax is interesting to certain groups of people (IDE writers, Java language tool producers, emacs/jedit-mode authors, etc.). Having access to the syntax is useful so these groups can start implementing Java language tools before the JDK 1.5 betas start arriving.

But I think it is too early to start this process, because the syntax is still to much in flux. Each JDK1.5 early-access compiler has made many changes to the previous, and the current is in fact quite different to the original syntaxes outlined JSR 14 and JSR 201.

Anyhoo, here are my notes.

Autoboxing

For the most part, autoboxing is incomplete in 2_2. This comment is from the CHANGES file:

Boxing and unboxing conversions are currently only implemented as argument conversions. It is almost certain that this is not what the JSR 201 expert group will specify. When we have more guidance from JSR 201, we will update the prototype.

So the last 3 lines of the following code does not compile, because only argument boxing is implemented. Note that the result of the last statement has been the a recent hot topic on the ADVANCED-JAVA list.

Map<String, Integer> m1 = new HashMap<String, Integer>();
m1.put("foo", new Integer(1));
m1.put("bar", 1); // boxed using Integer.valueOf(1)
m1.put("woz", null);
int i1 = m1.get("foo");
int i2 = m1.get("bar");
int i3 = m1.get("woz");

It seems that boxing of primitives is via a new valueOf() static method in each of the primitive-equiv classes. E.g. public static Integer valueOf(int i) {...} in java.lang.Integer. My guess is there will be an equivalent static method for unboxing (that will encode the policy for unboxing null to a primitive).

Varargs

You don't use the array brackets when declaring a vararg parameter now.

public static void println(Object... objs) {
    for (int i = 0; i < objs.length; i++) {
        System.out.print(objs[i]);
    }
    System.out.println();
}

Generics

Oh boy, Generics. Okay, the "variance" proposal is out, but they have added a "wildcard" syntax. These wild cards are useful when you want to say "some type parameter needs to be a subclass of some other parameter, but I don't care what". This is especially useful with the Collections API; you cannot store a List<Integer> into a List<Number> for example. This is best illustrated by this example:

List<Integer> l1 = new ArrayList<Integer>;
List<Number> l2 = new ArrayList<Double>;
...
l1.addAll(l2); // bad because l1 expects Integers, but at runtime gets Doubles

The current compiler allows 3 new forms: an extends bound wildcard <? extends E>, a super bounds wildcard <? super E>, and an unbound wildcard <?>. The following code illustrates these 3 forms. Understanding this code is left as an exercise to the reader.

List<Integer> src = new ArrayList<Integer>();
src.add(new Integer(1));
src.add(new Integer(2));
List<Number> numDest = new ArrayList<Number>();
List<Integer> intDest = new ArrayList<Integer>();
        
//addAll_1(src, numDest); // cannot call because addAll_1() is not specific enough
addAll_1(src, intDest);

addAll_2(src, numDest);
addAll_2(src, intDest);

addAll_3(src, numDest);
addAll_3(src, intDest);

addAll_4(src, numDest);
addAll_4(src, intDest);

count(numDest);
count(intDest);

public static <E> void addAll_1(List<E> src, List<E> dest) {
    // NB: didn't use for(E o : src) because of compiler bug
    for(Iterator<E> i = src.iterator(); i.hasNext(); ) {
        E o = i.next();
        dest.add(o);
    }
}

public static <E, T extends E> void addAll_2(List<T> src, List<E> dest) {
    for(Iterator<T> i = src.iterator(); i.hasNext(); ) {
        E o = i.next();
        dest.add(o);
    }
}

public static <T> void addAll_3(List<T> src, List<? super T> dest) {
    for(Iterator<T> i = src.iterator(); i.hasNext(); ) {
        dest.add(i.next());
    }
}

public static <E> void addAll_4(List<? extends E> src, List<E> dest) {
    dest.addAll(src);
}

public static int count(List<?> l)
{
    int count = 0;
    for (Object x : l) {
        count++;
    }
    return count;
}

Also note that the current compiler is "disallowing all of the constructs involving arrays that are not sound", for whatever that is worth.

enums

Okay, enums can be simple enough:

public enum Suit { clubs, diamonds, hearts, spades }

I think enum is going to deserve a blog entry in its own right. Did you know enums can have class bodies and constructors?

public enum Suit {
    clubs, diamonds, hearts("red"), spades("black");
    

    // constructors
    private Suit(String thing) {
        System.out.println("thing = " + thing);
    }
    private Suit() {
        System.out.println("no thing");
    }

    public boolean comingUpDiamonds() {
        return false;
    }
}

Did you know that each enum constant can have its own class body (each constant becomes an inner subclass)? (But this doesn't compile because the compiler throws a NPE.)

public enum Suit {
    clubs, diamonds,
    hearts("red") {
        public boolean comingUpDiamonds() { return true; }
    }
    ,
    spades("black");
    

    // constructors
    private Suit(String thing) {
        System.out.println("thing = " + thing);
    }
    private Suit() {
        System.out.println("no thing");
    }

    public boolean comingUpDiamonds() {
        return false;
    }
}

  • Home
  • Blog