Tech Ads
Back to Article List
Originally published April 2004 [ Publisher Link ]
JDK 1.5 : New language features
Version 1.5 of Sun Microsystems' Java Development Kit (JDK) is set to be released this summer and promises a list of features to ease the development of your Java applications. In this article we'll introduce you to many of the new features and provide code samples, so you can hit the ground running when the final release becomes available.
Grouping objects
Aggregating object instances is a common day-to-day task for a Java developer, either through vanilla arrays or the more comprehensive Collections Framework. (If you are unfamiliar with the Java Collections Framework, see the article Java Collections Framework : Grouping Java Objects .) Sun has added three new features to facilitate this task: generic types, auto-boxing and auto-unboxing of primitives, and an enhanced for
loop.
The need to extract and place values within a group is one of the issues that brought about the addition of generic types. In JDK 1.4 and previous versions, the placement of objects within a collections framework interface is done directly through the root Object class. This mechanism causes an explicit cast to be used for the extraction process, and makes it impossible to verify a class type at compile time.
Consider the following Java snippet:
ArrayList temperatures = new ArrayList(); temperatures.add(0, new Integer(79)); temperatures.add(1, new Integer(82)); temperatures.add(2, new String("Hot")); System.out.println( ( (Integer)temperatures.get(0)) ); System.out.println( ( (Integer)temperatures.get(1)) ); // The following is not a valid cast as the value is a String // It will compile, but will not be detected until run-time System.out.println( ( (Integer)temperatures.get(2)) ); |
Notice how we place three object instances in an ArrayList and then extract them with the get
method. All of the extractions require an explicit cast, and the actual cast is not checked until run time.
By using a generic type you can avoid this pitfall, as well as the explicit casting syntax. In order to declare a generic type you need to define the class type to be enclosed between < and >, as in the following code:
ArrayList<Integer> temperatures = new ArrayList<Integer>(); temperatures.add(0, new Integer(79)); temperatures.add(1, new Integer(82)); temperatures.add(2, new Integer(95)); System.out.println( (temperatures.get(0) )); System.out.println( (temperatures.get(1) )); System.out.println( (temperatures.get(2) )); |
Another issue surrounding the grouping of objects arises when you transitiong between primitives and class instances, and vice versa. Take for example when you need to perform a mathematical operation on a set of grouped objects. Since a Collection holds only objects, you need to use ancillary methods to convert an Integer
into an int
primitive:
ArrayList temperatures = new ArrayList(); temperatures.add(0, new Integer(79)); temperatures.add(1, new Integer(82)); temperatures.add(2, new Integer(95)); int sum = ((Integer)temperatures.get(0)).intValue() + ((Integer)temperatures.get(1)).intValue() + ((Integer)temperatures.get(2)).intValue(); double avg = sum / temperatures.size(); System.out.println(avg); |
Notice that besides the explicit cast used when extracting the Integer
object, we also employ the intValue()
method necessary for converting to a primitive. If we do not use this method the compiler will complain and force you to convert to a primitive in order to complete the operation. In version 1.5 of the JDK this conversion it automatically done by the compiler:
ArrayList<Integer> temperatures = new ArrayList<Integer>(); temperatures.add(0, new Integer(79)); temperatures.add(1, new Integer(82)); temperatures.add(2, new Integer(95)); int sum = temperatures.get(0) +temperatures.get(1)+ temperatures.get(2); double avg = sum / temperatures.size(); System.out.println(avg); |
Next
Another added feature in the new version is a shortcut for iterating over a set of data. While an Iterator
class along with its corresponding hasNext()
and next()
methods is the natural choice as of the current release, in the 1.5 version you will be able to use another variation, which automatically places the group's next value inside a field and makes it accessible throughout the loop's scope:
// In JDK 1.4 ArrayList temperatures = new ArrayList(); temperatures.add(0, new Integer(79)); temperatures.add(1, new Integer(82)); temperatures.add(2, new Integer(95)); for (Iterator i = temperatures.iterator(); i.hasNext();) { System.out.println(i.next()); } // Shortcut in JDK 1.5 ArrayList<Integer> temperatures = new ArrayList<Integer>(); temperatures.add(0, new Integer(79)); temperatures.add(1, new Integer(82)); temperatures.add(2, new Integer(95)); for (Integer i : temperatures) { System.out.println(i); } |
Other ins and outs
The newest JDK 1.5 also offers changes in the way you can output data, import and declare classes, and invoking methods.
Enumerated types is a feature that has long been awaited, especially by those with a C++ background. Although reasonable workarounds can be made in Java like using static final
fields, until now there was no explicit way to build this type of structure, which allows you to define a construct with a set of fixed values which do not change at run time. As of JDK 1.5 you will be able to use the following syntax:
public enum Software { openSource, closedSource }; |
Up until now, feeding variable input to a specific function could be a cumbersome procedure, since you had to overload the method's name with the distinct input variations you were expecting, like so:
theScoop(String title, Date published) { } theScoop(String title, String author, Date published) { } theScoop(Date Published, String author) { } Devchannel news = new Devchannel(); news.theScoop("JDK 1.5",new Date()); news.theScoop("JDK 1.5","D.R",new Date()); news.theScoop(new Date(),"D.R"); |
Now you will be able to use a special kind of syntax in the form of ...
(three dots, also known as an ellipsis) that allows you to feed a distinct number of fields on any invocation without overloading. You can simply loop through any set of data. Although you lose a safety net, you can now avoid the expense of writing scaffold code by using syntax like this:
theScoop(Object ... fields) { //Just loop through the fields } Devchannel news = new Devchannel(); news.theScoop("JDK 1.5",new Date()); news.theScoop("JDK 1.5","D.R",new Date()); news.theScoop(new Date(),"D.R"); |
The reading of input has also been enhanced through a class dubbed Scanner
, which allows you to parse any data stream in a succinct manner through special functions and regular expressions. Take the following Java code:
String input = "1 - Debian - 2 - RedHat - 3 - Suse"; Scanner s = Scanner.create(input).useDelimiter("\\s*-\\s*"); while (s.hasNext()) { System.out.println(s.nextInt()); System.out.println(s.next()); } s.close(); |
We define a Scanner
instance, which gets fed a String. The input is then split at each -
(dash) into distinct tokens by the useDelimiter
method, which takes a regular expression. Later we iterate over the data and print out each token.
Of special interest are the nextInt
and next
methods in Scanner
. Take for example nextInt
-- if upon loop execution the top token is not an integer, then the program throws an exception. In the context of the previous snippet, the use of these methods guarantees that only an even number of tokens be present, and that in each odd position an integer be declared.
Complementing this new mechanism for reading input, another class named Formatter
has been added that allows you to format any given output. For those familiar with C, it offers the same format mechanisms as the well-known C printf
function:
import java.util.*; import static java.util.Calendar.*; String event = new String("Linux was born : "); Calendar bday = new GregorianCalendar(1991, SEPTEMBER, 21); String s = String.format("%1$s %2$tA %2$tB %2$te %2$tY", event, bday); System.out.println(s); // Prints - Linux was born : Saturday September 21 1991 |
The format syntax is specified by a percentage sign, which is immediately preceded by the position of the object which is to be formated. In the previous code, the syntax is also preceded by a dollar sign, which is later followed by a letter indicating a specific format -- $s
for a string and $t
for a time format.
Finally, one more detail illustrated in the previous example is the use of static imports. As its name implies, a static import allows you to directly use static fields of a class inside your code without fully qualifying or inheriting the class. The GregorianCalendar
constructor shown above would normally require you to pass fully qualified fields in the form of a Calendar
class; however, with static imports, you can use the field syntax directly.
While these are most of the JDK's newest language features, the upcoming release also includes a series of improvements in the Java virtual machine itself, such as self-tuning of the Java heap and class data sharing, as well as new manageability capabilities available through Java Management Extensions -- all of which will offer you an edge in executing your existing applications and your newly minted Java code with 1.5 features.