Mustang Must-Haves: What’s Cool in Java SE 6

he long-awaited Java SE 6 is upon us. This latest version of the Java SE environment brings a number of new features and enhancements, such as integrated support for scripting languages and Web services, improved JDBC features, and an integrated Derby database (in the SDK release), as well as some nice management features and enhanced performance.

Writing a single article that details all the additional features and enhancements would be a difficult proposition. Instead, this article just highlights a few of my personal favorites in enough detail to be useful. In particular, it examines each of the following features in turn:

  • Scripting language support
  • JDBC 4 support
  • Monitoring and management
  • File system management

Support for Scripting Languages
Most developers have heard of, and possibly used, scripting languages such as PHP, Ruby, JavaScript, and Python. These dynamic languages are enjoying a resurgence in popularity, largely because of their flexibility and simplicity, and the productivity gains they promise.

Java 6 comes with built-in support for scripting languages. You can embed scripts in various scripting languages into your Java applications, passing parameters, evaluating expressions, and retrieving results. And you can do it all pretty seamlessly.

First of all, you obtain a new ScriptEngine object from a ScriptEngineManager, as shown here:

        ScriptEngineManager manager = new ScriptEngineManager();        ScriptEngine engine = manager.getEngineByName("js");

Each scripting language has its own unique identifier. The “js” here means you’re dealing with JavaScript.

Now you can start having some fun. Interacting with a script is easy and intuitive. You can assign scripting variables using the put() method and evaluate the script using the eval() method,. which returns the most recently evaluated expression processed by the script. And that pretty much covers the essentials. Here’s an example that puts it all together:

        engine.put("cost", 1000);        String decision = (String) engine.eval(            "if ( cost >= 100){ " +            "    decision = 'Ask the boss'; " +            "} else {" +            "    decision = 'Buy it'; " +            "}");        assert ("Ask the boss".equals(decision));

You can do more than just pass variables to your scripts? you can also invoke Java classes from within your scripts. Using the importPackage() function enables you to import Java packages, as shown here:

        engine.eval("importPackage(java.util); " +                    "today = new Date(); " +                    "print('Today is ' + today);");

Another cool feature is the Invocable interface, which lets you invoke a function by name within a script. This lets you write libraries in scripting languages, which you can use by calling key functions from your Java application. You just pass the name of the function you want to call, an array of Objects for the parameters, and you’re done! Here’s an example:

        engine.eval(            "function calculateInsurancePremium(age) {...}");        Invocable invocable = (Invocable) engine;        Object result           = invocable.invokeFunction("calculateInsurancePremium",                                     new Object[] {37});

You actually can do a fair bit more than what I’ve shown here. For example, you can pass a Reader object to the eval() method, which makes it easy to store scripts in external files, or bind several Java objects to JavaScript variables using a Map-like Binding object. You can also compile some scripting languages to speed up processing. But you probably get the idea that the integration with Java is smooth and well thought-out.

JDBC Enhancements
Java 6 comes with a number of neat new JDBC features, including an integrated, in-memory database. In fact, one of the more talked-about additions to the Java 6 JDK is Java DB, an integrated distribution of the Apache Derby (formerly IBM Cloudscape) database. Apache Derby is a lightweight, fully transactional, 100 percent Java embedded database. It is widely used in many open source Java applications, as it lets you simplify the installation process by providing a viable default in-memory database out of the box.

The built-in database lets developers easily set up and run fast-running unit tests against a real database, without the hassle of setting up and managing a test database environment. And by the time it gets into the production release, it should also support JDBC 4.0.

In Java 6, you no longer need to explicitly load the JDBC class. Remember the old Class.forName(“oracle.jdbc.driver.OracleDriver”)? In JDBC, you don’t need this line; the driver will be loaded whenever you obtain a new Connection from the DriverManager class, as shown here:

Connection conn         = DriverManager.getConnection("jdbc:derby:TestDB");

This will work with JDBC-compliant drivers, which are required to provide a META-INF/services/java.sql.Driver file. This file contains the class or classes that implement java.sql.Driver.

Now consider an example of what you will be able do with Derby and JDBC 4. First of all, you would create a new database. Suppose it is a simple in-memory database with just one CLIENT table and some sample data. You could create it as follows:

Connection conn    = DriverManager.getConnection("jdbc:derby:TestDB;create=true");Statement stmt = conn.createStatement();stmt.execute("create table CLIENT(ID int primary key,                                   FIRSTNAME varchar(40),                                   SURNAME varchar(40))");stmt.execute("insert into CLIENT values (1, 'Joe', 'Bloggs')");stmt.execute("insert into CLIENT values (2, 'Jane', 'Doe')");stmt.execute("insert into CLIENT values (3, 'John', 'Smith')");

Pretty easy stuff. This is typically the sort of thing you might do to set up an in-memory database for unit testing purposes. Note that other than the lack of the Class.forName() statement this code would also work with Derby in Java 5. From here on, however, the example leaves the realms of Java 5 completely and ventures into the new and uncharted lands of JDBC 4 and Java 6.

Monitoring and Management
Java 6 has made some good progress in the field of application monitoring, management, and debugging. The Java Monitoring and Management Console, or JConsole, is well known to system administrators who deploy Java applications (see Figure 1). First appearing in Java 5, JConsole is a graphical monitoring tool based on JMX, which provides a very complete view of the performance and resource consumption of Java applications.

Click to enlarge

One great thing about application monitoring in Java 6 is that you don’t need to do anything special to your application to use it. In Java 5, you needed to start any application that you wanted to monitor with a special command-line option (-Dcom.sun.management.jmxremote). In Java 6, you can monitor any application that is running in a Java 6 VM.

Java 6 comes with sophisticated thread-management and monitoring features as well. The Java 6 VM can now monitor applications for deadlocked threads involving object monitors and java.util.concurrent ownable synchronizers. If your application seems to be hanging, JConsole lets you check for deadlocks by clicking on the Detect Deadlock button in the Threads tab.

At a lower level, Java 6 helps resolve a common hard-to-isolate problem: the dreaded java.lang.OutOfMemoryError. In Java 6, an OutOfMemoryError will not just leave you guessing; it will print out a full stack trace so that you can have some idea of what might have caused the problem.

Managing the File System
Java 6 gives you much finer control over your local file system. For example, it is now easy to find out how much free space is left on your hard drive. The java.io.File class has the following three new methods to determine the amount of space available (in bytes) on a given disk partition:

	File homeDir = new File("/home/john");	System.out.println("Total space = " + homeDir.getTotalSpace());	System.out.println("Free space = " + homeDir.getFreeSpace());	System.out.println("Usable space = " + homeDir.getUsableSpace());

As their names would indicate, these methods return the total amount of disk space on the partition (getTotalSpace()), the amount of currently unallocated space (getFreeSpace()), and the amount of available space (getUsableSpace()), after taking into consideration OS-specific factors such as write permissions or other operating-system constraints. According to the documentation, getUsableSpace() is more accurate than getFreeSpace().

When I ran this code on my machine, it produced the following output:

	Total space = 117050585088	Free space = 100983394304	Usuable space = 94941515776

File permissions are another area where Java 6 brings new enhancements. The java.io.File class now has a set of functions allowing you to set the readable, writable, and executable flags on files in your local file system, as you would with the Unix chmod command. For example, to set read-only access to a file, you could do the following:

	File document = new File("document");	documentsDir.setReadable (true);	documentsDir.setWritable(false);	documentsDir.setExecutable (false);

This will set read-only access for the owner of the file. You can also modify the access rights for all users by setting the second parameter (ownerOnly) to false:

	documentsDir.setReadable (true, false);	documentsDir.setWritable(false, false);	documentsDir.setExecutable (false, false);

Naturally, this will work only if the underlying operating system supports this level of file permissions.

Just a Few of Many
Java 6 offers many other new features that I haven’t mentioned here, such as support for JAX-WS Web services and JAXB 2.0 XML binding, improvements in the Swing and AWT APIs, and language enhancements such as sorted sets and maps with bidirectional navigation. Try it out!

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles: