Wednesday, May 17, 2006

J2SE 5.0 in a Nutshell by Calvin Austin

Java 2 Platform Standard Edition (J2SE) 5.0 ("Tiger") is the next major revision to the Java platform and language; it is currently slated to contain 15 component JSRs with nearly 100 other significant updates developed through the Java Community Process (JCP).

NOTE: The external version number of this release is 5.0 and its internal version number is 1.5.0, as described at J2SE Naming and Versioning.

With so many exciting changes in this release, you may be wondering where you should start. As in previous releases, the comprehensive list of all changes is available in the Release notes guide. This article, from the J2SE team, will take you through the major changes so that you have a grasp of what J2SE 5.0 has to offer, before diving into the API docs.

The J2SE 5.0 release is focused along certain key themes:

There are a small number of features that are just as important but didn't neatly fit in with the themes; they are listed at the end:

Ease of Development

You may have already seen reports about some of the new Java Language changes that comprise the Ease of Development theme. The changes include generic types, metadata, autoboxing, an enhanced for loop, enumerated types, static import, C style formatted input/output, variable arguments, concurrency utilities, and simpler RMI interface generation.

JSR-201 contains four of these language changes; enhanced for loop, enumerated types, static import and autoboxing; JSR-175 specifies the new metadata functionality, while JSR-14 details generic types.

The new default language specification implemented by the javac compiler is version 5.0, also known as 1.5, so you do not need to supply the option -source 1.5 (as required in beta1).

Metadata

The metadata feature in J2SE 5.0 provides the ability to associate additional data alongside Java classes, interfaces, methods, and fields. This additional data, or annotation, can be read by the javac compiler or other tools, and depending on configuration can also be stored in the class file and can be discovered at runtime using the Java reflection API.

One of the primary reasons for adding metadata to the Java platform is to enable development and runtime tools to have a common infrastructure and so reduce the effort required for programming and deployment. A tool could use the metadata information to generate additional source code, or to provide additional information when debugging.

In beta2 we are pleased to announce the availability of an annotation processing tool called apt. Apt includes a set of new reflective APIs and supporting infrastructure to process program annotations. The apt reflective APIs provide a build-time, source-based, read-only view of program structure which cleanly models the Java programming language's type system. First, apt runs annotation processors that can produce new source code and other files. Next, apt can cause compilation of both original and generated source files, easing development. For more information on apt refer to the apt guide.

In the following example code you can additionally create an AnnotationFactory processor for apt to generate code or documentation when finding the debug annotation tag.

import java.lang.annotation.*;
import java.lang.reflect.*;

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface debug {
boolean devbuild() default false;
int counter();
}

public class MetaTest {
final boolean production=true;

@debug(devbuild=production,counter=1) public void testMethod() {
}


public static void main(String[] args) {

MetaTest mt = new MetaTest();
try {
Annotation[] a = mt.getClass().getMethod("testMethod").getAnnotations();
for (int i=0; i System.out.println("a["+i+"]="+a[i]+" ");
}
} catch(NoSuchMethodException e) {
System.out.println(e);
}
}
}

With a metadata processing tool, many repetitive coding steps could be reduced to a concise metadata tag. For example, the remote interface required when accessing a JAX-RPC service implementation could be implemented as follows:

Before

public interface PingIF extends Remote {
public void ping() throws RemoteException;
}

public class Ping implements PingIF {
public void ping() {
}
}

After

public class Ping {
public @remote void ping() {
}
}

Generic Types

Generic types have been widely anticipated by the Java Community and are now part of J2SE 5.0. One of the first places to see generic types in action is the Collections API. The Collections API provides common functionality like LinkedLists, ArrayLists and HashMaps that can be used by more than one Java type. The next example uses the 1.4.2 libraries and the default javac compile mode.

ArrayList list = new ArrayList();
list.add(0, new Integer(42));
int total = ((Integer)list.get(0)).intValue();

The cast to Integer on the last line is an example of the typecasting issues that generic types aim to prevent. The issue is that the 1.4.2 Collection API uses the Object class to store the Collection objects, which means that it cannot pick up type mismatches at compile time. The first notification of a problem is a ClassCastException at runtime.

The same example with the generified Collections library is written as follows:

ArrayList list =  new ArrayList();
list.add(0, new Integer(42));
int total = list.get(0).intValue();

The user of a generified API has to simply declare the type used at compile type using the <> notation. No casts are needed and in this example trying to add a String object to an Integer typed collection would be caught at compile time.

Generic types therefore enable an API designer to provide common functionality that can be used with multiple data types and which also can be checked for type safety at compile time.

Designing your own Generic APIs is a little more complex that simply using them. To get started look at the java.util.Collection source and also the API guide.

Autoboxing and Auto-Unboxing of Primitive Types

Converting between primitive types, like int, boolean, and their equivalent Object-based counterparts like Integer and Boolean, can require unnecessary amounts of extra coding, especially if the conversion is only needed for a method call to the Collections API, for example.

The autoboxing and auto-unboxing of Java primitives produces code that is more concise and easier to follow. In the next example an int is being stored and then retrieved from an ArrayList. The 5.0 version leaves the conversion required to transition to an Integer and back to the compiler.

Before

ArrayList list = new ArrayList();
list.add(0, new Integer(42));
int total = (list.get(0)).intValue();

After

ArrayList list = new ArrayList();
list.add(0, 42);
int total = list.get(0);

Enhanced for Loop

The Iterator class is used heavily by the Collections API. It provides the mechanism to navigate sequentially through a Collection. The new enhanced for loop can replace the iterator when simply traversing through a Collection as follows. The compiler generates the looping code necessary and with generic types no additional casting is required.

Before

ArrayList list = new ArrayList();
for (Iterator i = list.iterator(); i.hasNext();) {
Integer value=(Integer)i.next();
}

After

ArrayList list = new ArrayList(); 
for (Integer i : list) { ... }

Enumerated Types

This type provides enumerated type when compared to using static final constants. If you have previously used the identifier enum in your own application, you will need to adjust the source when compiling with javac -source 1.5 (or its synonym -source 5).

public enum StopLight { red, amber, green };

Static Import

The static import feature, implemented as "import static", enables you to refer to static constants from a class without needing to inherit from it. Instead of BorderLayout.CENTER each time we add a component, we can simply refer to CENTER.

import static java.awt.BorderLayout.*;

getContentPane().add(new JPanel(), CENTER);

Formatted Output

Developers now have the option of using printf-type functionality to generate formatted output. This will help migrate legacy C applications, as the same text layout can be preserved with little or no change.

Most of the common C printf formatters are available, and in addition some Java classes like Date and BigInteger also have formatting rules. See the java.util.Formatter class for more information. Although the standard UNIX newline '\n' character is accepted, for cross-platform support of newlines the Java %n is recommended.

System.out.printf("name count%n");
System.out.printf("%s %5d%n", user,total);

Formatted Input

The scanner API provides basic input functionality for reading data from the system console or any data stream. The following example reads a String from standard input and expects a following int value.

The Scanner methods like next and nextInt will block if no data is available. If you need to process more complex input, then there are also pattern-matching algorithms, available from the java.util.Formatter class.

Scanner s= new Scanner(System.in);
String param= s.next();
int value=s.nextInt();
s.close();

Varargs

The varargs functionality allows multiple arguments to be passed as parameters to methods. It requires the simple ... notation for the method that accepts the argument list and is used to implement the flexible number of arguments required for printf.

void argtest(Object ... args) {
for (int i=0;i }
}

argtest("test", "data");

Concurrency Utilities

The concurrency utility library, led by Doug Lea in JSR-166, is a special release of the popular concurrency package into the J2SE 5.0 platform. It provides powerful, high-level thread constructs, including executors, which are a thread task framework, thread safe queues, Timers, locks (including atomic ones), and other synchronization primitives.

One such lock is the well known semaphore. A semaphore can be used in the same way that wait is used now, to restrict access to a block of code. Semaphores are more flexible and can also allow a number of concurrent threads access, as well as allow you to test a lock before acquiring it. The following example uses just one semaphore, also known as a binary semaphore. See the java.util.concurrent package for more information.

final  private Semaphore s= new Semaphore(1, true);

s.acquireUninterruptibly(); //for non-blocking version use s.acquire()

try {
balance=balance+10; //protected value
} finally {
s.release(); //return semaphore token
}

rmic -- The RMI Compiler

You no longer need to use rmic, the rmi compiler tool, to generate most remote interface stubs. The introduction of dynamic proxies means that the information normally provided by the stubs can be discovered at runtime. See the RMI release notes for more information.

Scalability and Performance

The 5.0 release promises improvements in scalability and performance, with a new emphasis on startup time and memory footprint, to make it easier to deploy applications running at top speed.

One of the more significant updates is the introduction of class data sharing in the HotSpot JVM. This technology not only shares read-only data between multiple running JVMs, but also improves startup time, as core JVM classes are pre-packed.

Performance ergonomics are a new feature in J2SE 5.0. This means that if you have been using specialized JVM runtime options in previous releases, it may be worth re-validating your performance with no or minimal options.

Monitoring and Manageability

Monitoring and Manageability is a key component of RAS (Reliability, Availability, Serviceability) in the Java platform.

The J2SE 5.0 release provides comprehensive monitoring and management support: instrumentation to observe the Java virtual machine, Java Management Extensions (JMX) framework, and remote access protocols. All this is ready to be used out-of-the-box. (See the Management and Monitoring release notes for more details.)

The JVM Monitoring & Management API specifies a comprehensive set of instrumentation of JVM internals to allow a running JVM to monitored. This information is accessed through JMX (JSR-003) MBeans and can accessed locally within the Java address space or remotely using the JMX remote interface (JSR-160) and through industry-standard SNMP tools.

One of the most useful features is a low memory detector. JMX MBeans can notify registered listeners when the threshold is crossed, see javax.management and java.lang.management for details.

J2SE 5.0 provides an easy way to enable out-of-the-box remote management of JVM and an application (see Out-of-the-Box for details). For example, to start an application to be monitorable by jconsole in the same local machine, use the following system property:

java -Dcom.sun.management.jmxremote -jar Java2Demo.jar

and to monitor it remotely through JMX without authentication:

java -Dcom.sun.management.jmxremote.port=5001
-Dcom.sun.management.jmxremote.ssl=false
-Dcom.sun.management.jmxremote.authenticate=false -jar Java2Demo.jar

For an idea of how easy the new API is to use, the following reports the detailed usage of the memory heaps in the HotSpot JVM.

import java.lang.management.*;
import java.util.*;

public class MemTest {
public static void main(String args[]) {
List pools = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean p: pools) {
System.out.println("Memory type="+p.getType()+" Memory usage="+p.getUsage());
}
}
}

New JVM Profiling API (JSR-163)

The release also contains a more powerful native profiling API called JVMTI. This API has been specified through JSR-163 and was motivated by the need for an improved profiling interface. However, JVMTI is intended to cover the full range of native in-process tools access, which in addition to profiling, includes monitoring, debugging and a potentially wide variety of other code analysis tools.

The implementation includes a mechanism for bytecode instrumentation, Java Programming Language Instrumentation Services (JPLIS). This enables analysis tools to add additional profiling only where it is needed. The advantage of this technique is that it allows more focused analysis and limits the interference of the profiling tools on the running JVM. The instrumentation can even be dynamically generated at runtime, as well as at class loading time, and pre-processed as class files.

The following example creates an instrumentation hook that can load a modified version of the class file from disk. To run this test, start the JRE with java -javaagent:myBCI BCITest

//File myBCI.java
import java.lang.instrument.Instrumentation;

public class myBCI {
private static Instrumentation instCopy;

public static void premain(String options, Instrumentation inst) {
instCopy = inst;
}
public static Instrumentation getInstrumentation() {
return instCopy;
}
}

//File BCITest.java

import java.nio.*;
import java.io.*;
import java.nio.channels.*;
import java.lang.instrument.*;

public class BCITest {
public static void main (String[] args) {
try {
OriginalClass mc = new OriginalClass();
mc.message();

FileChannel fc=new FileInputStream(
new File("modified"+File.separator+"OriginalClass.class")).getChannel();
ByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());
byte[] classBuffer = new byte[buf.capacity()];
buf.get(classBuffer, 0, classBuffer.length);
myBCI.getInstrumentation().redefineClasses(
new ClassDefinition[] {
new ClassDefinition(mc.getClass(), classBuffer)});
mc.message();
}catch (Exception e){}
}
}

//OriginalClass.java
//Compile in current directory
//Copy source to modified directory,change message and recompile

public class OriginalClass {
public void message() {
System.out.println("OriginalClass");
}
}

Improved Diagnostic Ability

Generating Stack traces has been awkward if no console window has been available. Two new APIs, getStackTrace and Thread.getAllStackTraces provide this information programmatically.

StackTraceElement e[]=Thread.currentThread().getStackTrace();
for (int i=0; i System.out.println(e[i]);
}
System.out.println("\n"+Thread.getAllStackTraces());

The HotSpot JVM includes a fatal error handler that can run a user-supplied script or program if the JVM aborts. A debug tool can also connect to a hung JVM or core file using the HotSpot JVM serviceability agent connector.

-XX:OnError="command" 


-XX:OnError="pmap %p"
-XX:OnError="gdb %p"

optional %p used as process id

Desktop Client

The Java Desktop client remains a key component of the Java platform and as such has been the focus of many improvements in J2SE 5.0.

This Beta release contains some of the early improvements in startup time and memory footprint. Not only is the release faster, but the Swing toolkit enjoys a fresh new theme called Ocean. And by building on the updates in J2SE 1.4.2, there are further improvements in the GTK skinnable Look and Feel and the Windows XP Look and Feel.


Linux and Solaris users, and new in beta2, Windows users, who have the latest OpenGL drivers and select graphic cards can get native hardware acceleration from Java2D using the following runtime property:

java -Dsun.java2d.opengl=true -jar Java2D.jar

The Linux release also has the fast X11 toolkit, called XAWT, enabled by default. If you need to compare against the motif version you can use the following system property:

java -Dawt.toolkit=sun.awt.motif.MToolkit -jar Notepad.jar

(the X11 toolkit is called sun.awt.X11.XToolkit)

The X11 Toolkit also uses the XDnD protocol so you can drag-and-drop simple components between Java and other applications like StarOffice or Mozilla.

Miscellaneous Features

Core XML Support

J2SE 5.0 introduces several revisions to the core XML platform, including XML 1.1 with Namespaces, XML Schema, SAX 2.0.2, DOM Level 3 Support and XSLT with a fast XLSTC compiler.

In addition to the core XML support, future versions of the Java Web Services Developer Pack will deliver the latest web services standards: JAX-RPC & SAAJ (WSDL/SOAP), JAXB, XML Encryption, and Digital Signature and JAXR for registries.

Supplementary Character Support

32-bit supplementary character support has been carefully added to the platform as part of the transition to Unicode 4.0 support. Supplementary characters are encoded as a special pair of UTF16 values to generate a different character, or codepoint. A surrogate pair is a combination of a high UTF16 value and a following low UTF16 value. The high and low values are from a special range of UTF16 values.

In general, when using a String or sequence of characters, the core API libraries will transparently handle the new supplementary characters for you. However, as the Java "char" still remains at 16 bits, the very few methods that used char as an argument now have complementary methods that can accept an int value which can represent the new larger values. The Character class in particular has additional methods to retrieve the current character and the following character in order to retrieve the supplementary codepoint value as below:

String u="\uD840\uDC08";
System.out.println(u+"+ "+u.length());
System.out.println(Character.isHighSurrogate(u.charAt(0)));
System.out.println((int)u.charAt(1));
System.out.println((int)u.codePointAt(0));

See the Unicode section in Character for more details.

JDBC RowSets

There are five new JDBC RowSet class implementations in this release. Two of the most valuable ones are CachedRowSet and WebRowSet. RowSet objects, unlike ResultSet objects, can operate without always being connected to a database or other data source. Without the expensive overhead of maintaining a connection to a data source, they are much more lightweight than a ResultSet object. The CachedRowSet contains an in-memory collection of rows retrieved from the database that can, if needed, be synchronized at a later point in time. The WebRowSet implementation, in addition, can write and read the RowSet in XML format.

The following code fragment shows how easy it is to create and use a WebRowSet object.

Class.forName("org.postgresql.Driver");
WebRowSetImpl wrs = new WebRowSetImpl();
wrs.setCommand("SELECT COF_NAME,TOTAL FROM COFFEES");

wrs.setUsername("postgres");
wrs.setPassword("");
wrs.setUrl("jdbc:postgresql:test");
wrs.execute(); // executes command and populates webset all coffees

wrs.absolute(1); // moves cursor to the first row of wrs
wrs.updateInt(2, 10); // reset total field to 10
wrs.updateRow(); // finishes edits to this row
wrs.acceptChanges(); // writes new total to the data source
wrs.writeXml(System.out); // also exports rowset in XML format
wrs.close();

References

New Language Features for Ease of Development in the Java 2 Platform Standard Edition 5.0: http://java.sun.com/features/2003/05/bloch_qa.html

Tiger Component JSRs

003 Java Management Extensions (JMX) Specification http://jcp.org/en/jsr/detail?id=3

013 Decimal Arithmetic Enhancement http://jcp.org/en/jsr/detail?id=13

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

028 Java SASL Specification http://jcp.org/en/jsr/detail?id=28

114 JDBC Rowset Implementations http://jcp.org/en/jsr/detail?id=114

133 Java Memory Model and Thread Specification Revision http://jcp.org/en/jsr/detail?id=133

160 Java Management Extensions (JMX) Remote API 1.0 http://jcp.org/en/jsr/detail?id=160

163 Java Platform Profiling Architecture http://jcp.org/en/jsr/detail?id=163

166 Concurrency Utilities http://jcp.org/en/jsr/detail?id=166

174 Monitoring and Management Specification for the Java Virtual Machine http://jcp.org/en/jsr/detail?id=174

175 A Metadata Facility for the Java Programming Language http://jcp.org/en/jsr/detail?id=175

200 Network Transfer Format for Java Archives http://jcp.org/en/jsr/detail?id=200

201 Extending the Java Programming Language with Enumerations, Autoboxing, Enhanced for Loops and Static Import http://jcp.org/en/jsr/detail?id=201

204 Unicode Supplementary Character Support http://jcp.org/en/jsr/detail?id=204

206 Java API for XML Processing (JAXP) 1.3 http://jcp.org/en/jsr/detail?id=206


No comments: