New features in Java 1.5

This article was originally published in VSJ, which is now part of Developer Fusion.
Ease of use is the new mantra at Sun, with its long-stated aim of attracting 10 million developers to the Java platform. One aspect of this new ease-of-use zeal is to make the language easier to develop in, and Java 1.5 (Tiger) has been released in beta accommodating some of these aims.

The other element of this usability drive is a new NetBeans-based IDE, Studio Creator (formerly Project Rave), which will be released shortly to the development community.

This article will examine some of the new features available in Tiger.

New features

Although there are fairly extensive changes to the underlying language, some changes are simply the bolting on of APIs to the standard. For instance, Tiger now includes the JMX (Java Management eXtensions) API as standard, allowing your Java applications to be integrated into SNMP for management and monitoring. I will concentrate mainly on the language changes, although I will address those areas where APIs have been added to the standard Java distribution.

Annotations

Any developer familiar with the .NET languages will be familiar with using attributes to mark up their code. Java now includes a similar facility, known as annotations. In some ways this facility is an improvement on the .NET attributes facility. To create an annotation, you simply define an interface which has methods which are populated as name value pairs by the developer. These values can be read by the compiler, or more likely a deployment tool of some sort. As a developer, you define the target that this attribute can be applied to, and a retention policy (more on this shortly). For instance you may create a WebMethod annotation something like this:
public @interface WebMethod {
	String description() default
		"A Web Method";
	String messageName();
}
This annotation has two values, description and messageName which can have String values provided by the developer, which can then be read by deployment tools. A developer populates this metadata as shown here:
public class Foo {
	@WebMethod(description=
		"A great method",
		messageName="bar")
	public void foo() {
		// do stuff
	}
}
By default, annotations are compiled into the class file, but are not available to the runtime environment. You can specify one of three retention policies, namely:
  • The annotation is visible in source, but discarded in the compiled class file
  • The annotation is compiled into the class file
  • The annotation can be examined at runtime via reflection
The example below shows how to specify a runtime retention policy, and how to reflect this class at runtime to retrieve the annotation values.
import java.lang.annotation.*;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Author {
	String name();
}

@Author(name="James Winters")
public class AuthorTest {
	public static void
			main(String[] args) {
		AuthorTest test =
			new AuthorTest();
		Annotation[] a =
			test.getClass().
			getAnnotations();
		for (int i=0; i<a.length; i++){
			System.out.println(a[i]);
} } }
You can specify any combination of eight targets using the standard @Target annotation. This simply means that you can apply the Annotation to that type of program element. If you do not provide a @Target annotation, then you can decorate any type of program element. The permissible targets are listed below, and are self-explanatory:
TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,
LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE

Generics

The language now has the ability to declare parameterized types, in a manner which will appear very familiar to C++ programmers. The fact that a type can contain generic types is simply indicated by adding a <T> element to your class declaration, where T is a type parameter indicating your class will have its type information supplied at runtime, as shown in this code snippet for a Stack class capable of being parameterised.
import java.util.*;
public class Stack<T> {
	private ArrayList<T> items;
	public Stack() {
		items = new ArrayList<T>();
	}
	public void Push( T item ) {
		items.add(item);
	}
	public T Pop() {
		T result = items.remove(
			items.size()-1);
		return result;
	}
}
To use this Stack class you simply need to provide the type which your stack is capable of holding. Note this needs to be a reference type, and not a primitive. The code showing how to do this is given below.
public class StackTest {
	public static void
			main(String[] args) {
		Stack<Integer> s =
			new Stack<Integer>();
		for( int i = 10; i < 100;
				i+= 10 ) {
			System.out.printf(
				"Pushing %d \n", i );
			s.Push( i );
		}
		for(int i = 90; i > 0; i-=10) {
			int temp = s.Pop();
			System.out.printf(
				"Popping %d,	Expecting
				%d\n",temp, i);
} } }
If you’re paying careful attention, you’ll notice this code looks like a bit odd. The pop and push methods are expecting to receive and return Integers, but you’re passing ints around. Java 1.5 now supports automatic boxing and unboxing of primitive types and their equivalent wrappers. And if you’re an old C programmer at heart, you’ll be glad to see the inclusion of a printf method.

Enumerations

Those of you who are tired of having to use final static constants to simulate enums will be happy to see the inclusion of enum in the language, even if they are subtly different to the C style of enumeration. And to make them even easier to use statics can now be imported from a class so you don’t have to use constructs like TrafficLight.GREEN any more. Switch statements have been modified to include enums, although as enums are types it is probably far better to include methods in the type safe enumeration, since in a well-designed OO system switch statements should be avoided.
public enum TrafficLight {
	Red,Amber,Green;
}

public class LightTest {
	TrafficLight go = TrafficLight.Green;
}

Other features

The language now supports a facility to iterate around collections, rather like foreach, although in true Java style the for loop has simply been overloaded to use the : notation. You can also now send a variable amount of arguments to a method, using the … notation, as shown below:
import java.util.*;
public class ArgsTest {
	private ArrayList<String> data =
		new ArrayList<String>();
	void argtest(String ... args) {
		for(int i=0;i<args.length;i++){
			data.add(args[i]);
		}
	}
	public static void
			main(String[] args) {
		ArgsTest test = new ArgsTest();
		test.argtest("The", "quick",
			"brown", "fox");
		int count = 0;
		for (String s : test.data) {
			System.out.printf(
				"Element %d contains
				%s \n",++count,s);
} } }
One of the best uses of nested classes (inner static classes) is as a grouping mechanism, similar to packages, but enforcing more cohesion. This, however, leads to using code like Math.abs() , and while this is fine for methods, for constants it can make for long declarations, as in the following swing code:
setDefaultCloseOperation(
	WindowConstants.DISPOSE_ON_CLOSE);
The import static clause simply allows you to specify that you are importing the static declarations from the enclosing class, much like the code below.
import javax.swing.*;
import java.awt.*;
// the following imports are actually
// unneccessary JFrame implements the 
// interface WindowConstants and 
// SwingConstants but you get the 
// idea.

import static
	javax.swing.WindowConstants.*;
import static
	javax.swing.SwingConstants.*;
import static java.lang.Math.*;
public class StaticImportTest extends
		JFrame {
	public static void
			main(String[] args) {
		StaticImportTest test =
			new StaticImportTest();
		test.setSize(300,300);
	test.setDefaultCloseOperation(
			DISPOSE_ON_CLOSE);
		Container c =
			test.getContentPane();
		c.setLayout(new FlowLayout());
		JLabel label =
			new JLabel("Right Aligned
			Label",RIGHT);
		JTextField text =
			new JTextField(""+random());
		c.add(label);
		c.add(text);
		test.setVisible(true);
	}
}
Most Java developers have been frustrated in the past by having no real output format control and having to use complex Formatter objects to format input. Many of these problems have been reduced by supporting the use of printf for formatted output, and introducing a new Scanner API for formatting input.

However, unlike in C, if a flag is passed to printf of the wrong type, it is not simply ignored, but an exception IllegalFormatConversionException will be thrown. The Scanner API simply converts an input stream into a series of Tokens. The delimiters between each token can be specified using regular expressions, and primitive values can be read from the Token. Example usage shown below

String str = "1.0,2.1,3.4,4.0";
Scanner scanner = Scanner.create(str);
scanner.useDelimiter("\\s*,\\s*");
while (scanner.hasNextFloat()) {
	float f = scanner.nextFloat();
	System.out.printf("Have read
		%1$5.2f from input\n",f);
For those developers writing concurrent applications, this release of Java has been strengthened by including Doug Lea’s concurrency package in the namespace java.util.concurrency. A full treatment of the types available for use in this package lies outside the scope of this article.

Instrumentation

As already mentioned, Java 1.5 includes full support for JMX, but it also includes a new standard way of measuring JVM performance, which hopefully spells the end of java – Xrunhprof to run the heap profiler. This package, java.lang.instrument, allows you as a developer to create agent classes which will be preloaded into the JVM before the main class. The java command line tool has been altered to have a javaagent switch, which is simply a listing of all the agents you have created which must be preloaded. These agents can then interact with the JVM to provide profiling information.
import java.lang.instrument.
	Instrumentation;
public class SizerTest {
	private static Instrumentation
		instrumentation;
	public static void premain(String
		options, Instrumentation inst){
		instrumentation = inst;
	}
	public static void
			main(String[] args) {
		Object obj = new Object();
		long size =
instrumentation.getObjectSize(obj);
		System.out.printf("The object
			is %1$d bytes",size);
	}
}

A call to action

Navigate to the Sun web site www.javasoft.com and download the Beta 1 of Java 1.5 and try a few of these options. A good starter point is the source code for these demos. Make sure that when you compile them you use the switch – source 1.5 or javac will revert to creating 1.4 class files. Examine your code to see where you can take advantage of these new features to make your code more readable, maintainable and robust. Participate in the developers forums to provide feedback and bug reports, and in a few months time you’ll have a development platform that you’ll be comfortable using.

So, in conclusion, the Tiger is definitely burning bright, and this release of the J2SE is guaranteed to help you craft better systems.


James Winters is a Principal technologist at QA, where he specialises in training development, course delivery and product consulting on Java technology.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“God could create the world in six days because he didn't have to make it compatible with the previous version.”