Java 1.5 New Features


A complete list of the new features in Java 1.5 can be found at Sun's website. We will be going over a few of the features here, with short code samples.

Generics

Generics are similar to C++-style templates, in declaration and in use. In the past, generic collections, such as Vector or ArrayList returned a generic object reference which had to be casted. For example

Vector v = new Vector();
for (int i = 0; i < 100; i++)
     v.add(new Integer(i));
Integer g = v.get(0); //This doesnŐt work since v.get(0) returns an Object!
Integer g = (Integer)v.get(0); //Now this works


Now, the new 1.5-based code which uses generics:

Vector v <Integer> = new Vector<Integer>();
for (int i = 0; i < 100; i++)
     v.add(new Integer(i));
Integer g = v.get(0); //Works perfectly!


Generics can have one or two type parameters. For example, let's say we want to match the digits to their names:

HashMap digits <Integer, String> = new HashMap <Integer, String>();
digits.put(1, "one");
digits.put(2, "two");
...
int i = 1;
String name = digits.get(i); //Wow, this is nice


Here's how one would create a simple class that uses generics:

public class StoreIt <T>
{
     private T it;
     public void set(T x)
     {
          it = x;
     }
     public T get()
     {
          return it;
     }
}


With wildcards, one can be more specific about what types the program can work with. For example, a graphics function can accept only lists of objects that extend Shape:

public void drawAll(List<? extends Shape> shapes) { ... }


Also, we can specify a wildcard with no bounds, if we want to work with an object of any type whatsoever:

public void print(List <?> things) { }

Varargs

Prior to Java 5, a method that took an arbitrary number of values required you to place the values in an array and pass the array as an argument to the method. While it is true that the multiple values must still be passed in as an array, this process can be hidden with varargs.

Consider the following code:

void foo(String someString, int[] argList) {
     //do something
}


Using varargs, this can be rewritten:

void bar(String someString, int... argList) {
     //do something
}


The "..." after the final parameter's type specifies that an arbitrary number of integers can be passed in after the first String object. Varargs can only be used in the final argument position. Now, if you want to call foo in your code, your only choice is to do the following:

int[] args = {1,2,3,4};
foo("str",args);


With bar, you can choose to use an array to pass in the arguments like before, but you also have the ability to place the values directly into the method call:

bar("str", 1, 2, 3, 4);

Inside the method, the set of arguments passed in using varargs is represented as an array, so bar behaves just like foo internally. As a precaution, you should avoid overloading a varargs method because it can be difficult to discern which overloading gets called.

          Copyright 2004 Sun MicroSystems, Inc.

Autoboxing

In Java, you cannot put a primitive value into a collection. For example, if you wanted to keep a collection of integers, you would have to box the primitive values in instances of the Integer wrapper class and then insert the objects into the collection. When you take an object out of the collection, you get the same Integer object that you put in. In order to get the primitive value, you must unbox the object using the intValue method. With autoboxing, the process of boxing and unboxing is done for you, making code easier to read and write.

import java.util.*;
public class Test {
     public static void main(String[] args) {
          Vector v = new Vector();

          // 10 is boxed in an Integer
          v.add(10);

          Integer numObj = new Integer(10);

          // The value of numObj is unboxed and added to 1 before being stored in num
          int num = numObj + 1;

          // numObj is unboxed, incremented, and boxed again
          numObj++;
     }
}


Autoboxing makes it easy to ignore the distinction between primitive data types and their associated wrapper classes. There are few important things to consider when using autoboxing, however:

An Object can have a null value. If you try to autounbox null, in will throw a NullPointerException.

The == operator performs reference identity comparisons on Integer expressions and value comparisions on int expressions (The same applies for the other primitive types). The following code snippet illustrates this behavior:

Integer x = new Integer(10);
Integer y = new Integer(10);
int z = 10;

System.out.println(x == y); //prints false
System.out.println(x == z); //prints true


There is a performance penalty associated with boxing and unboxing.
Because of the performance penalty involved with boxing/unboxing, you should only use them when using a primitive type is not an option (when using Collections, for example).

          Copyright 2004 Sun MicroSystems, Inc.

Static Imports

Do you hate typing in Math.sqrt() or System.out.println() everytime you want to use a static member of a built-in Java class? Then Java 1.5 has something just for you, static imports!
You can turn code that looks like this:

double someNum = Math.cos(Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2,2))) + Math.PI;

Into something like this:

import static java.lang.Math.*;
double someNum = cos(sqrt(pow(x1-x2, 2) + pow(y1-y2,2))) + PI;


But be careful, static imports make code hard to read, and if you import all of the members of a certain class (like Math.*), you might end up importing static methods that have the same name as methods you've already written.

Enums

Package: java.lang.Enum<E>

In General, Enums in java look very much like the C, C++, and C# representations.

enum Season { WINTER, SPRING, SUMMER, FALL }

Basically in other program languages, enums are just glorified integers and do not provide much power to use them. Java on the other hand takes enums to the next step. Since enums are a class, they allows you to add arbitrary methods and fields to an enum type and to implement arbitrary interfaces. Enum types provide implementations of all the Object methods and they are Comparable and Serializable.

import java.util.*; public class Card {
     public enum Rank { DEUCE, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE };
     public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES };

     private final Rank rank;
     private final Suit suit;
     private Card(Rank rank, Suit suit) {
          this.rank = rank;
          this.suit = suit;
     }

     public Rank rank() { return rank; }
     public Suit suit() { return suit; }
     public String toString() { return rank + " of " + suit; }

     private static final List protoDeck = new ArrayList();

     // Initialize prototype deck
     static {
           for (Suit suit : Suit.values())
                for (Rank rank : Rank.values())
                          protoDeck.add(new Card(rank, suit));
     }

     public static ArrayList newDeck() {
           return new ArrayList(protoDeck); // Return copy of prototype deck
      }
}


You can see that we use the method values() instead of manually tracking like in C and C++. This is great for implementing a for-each iteration on an array structure.

You can also provide data for the enums unlike in c and c++

public enum Planet {
    MERCURY (3.303e+23, 2.4397e6),
    VENUS   (4.869e+24, 6.0518e6),
    EARTH   (5.976e+24, 6.37814e6),
    MARS    (6.421e+23, 3.3972e6),
    JUPITER (1.9e+27,   7.1492e7),
    SATURN  (5.688e+26, 6.0268e7),
    URANUS  (8.686e+25, 2.5559e7),
    NEPTUNE (1.024e+26, 2.4746e7),
    PLUTO   (1.27e+22,  1.137e6);

    private final double mass;   // in kilograms
    private final double radius; // in meters
    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }
    public double mass()   { return mass; }
    public double radius() { return radius; }

    // universal gravitational constant  (m3 kg-1 s-2)
    public static final double G = 6.67300E-11;

    public double surfaceGravity() {
        return G * mass / (radius * radius);
    }
    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity();
    }
}

You also see here the ability to define methods for the values in
the enum structure.


We can also define behaviors for each element in the enum structure

public enum Operation {
  PLUS   { double eval(double x, double y) { return x + y; } },
  MINUS  { double eval(double x, double y) { return x - y; } },
  TIMES  { double eval(double x, double y) { return x * y; } },
  DIVIDE { double eval(double x, double y) { return x / y; } };

  // Do arithmetic op represented by this constant
  abstract double eval(double x, double y);
}

Formatter

Package: java.util.Formatter

This class is basically a printf for java. Although it is very similar to the printf in C, there have been changes made to accommodate java better and even exploit some of the features. Another major difference between C is that the java Formatter is strict when dealing with incompatibility. In C, the flag is silently ignored while in java, an exception is thrown. Formatter also provides support for layout justification and alignment, common formats for numeric, string, and date/time data, and locale-specific output. It also support BigDecimal and Calendar classes.

String Builder sb = new StringBuilder();
// Send all output to the Appendable object sb
Formatter formatter = new Formatter(sb, Locale.US);

// Explicit argument indices may be used to re-order output.
formatter.format("%4$2s %3$2s %2$2s %1$2s", "a", "b", "c", "d")
// -> " d c b a"

// The '(' numeric flag may be used to format negative numbers with
// parentheses rather than a minus sign. Group separators are
// automatically inserted.
formatter.format("Amount gained or lost since last statement: $%(,.2f", balanceDelta);
// -> "Amount gained or lost since last statement: $ (6,217.58)"

Format text to the system.out and system.err

// Writes a formatted string to System.out.
System.out.format("Local time: %tT", Calendar.getInstance());
// -> "Local time: 13:34:18"

// Writes formatted output to System.err.
System.err.printf("Unable to open file '%1$s': %2$s",fileName, exception.getMessage());
// -> "Unable to open file 'food': No such file or directory"


The general format syntax is the following:

%[argument_index$][flags][width][.precision]conversion


To see a list of all the flags go to:
           http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html