Year in Review: What to expect in Java SE 7

An overview of features in and out of the next Java specification

Since early 2007, Alex Miller has been diligently tracking and sharing information about the JSRs proposed for inclusion in Java SE 7. In this Year in Review feature, he shares the fruits of his labor: a plausible picture of the forthcoming platform specification, including some of the most recent announcements from Sun Microsystems. Get an overview of the key improvements we're likely to see in Java SE 7, and find out which promising JSRs might not make it in after all.

Almost immediately after Java SE 6 was released in December 2006, developers began to cast an eye toward which JSRs might be included in Java SE 7. In January 2007 I started tracking these ideas and cataloging the conversations about them, many of which take place in the blogosphere. As time has passed, some ideas have sprouted JSRs, specifications, and prototypes, while others have withered and dropped out of sight.

A good picture has emerged of which JSRs and language changes are likely to be included because of their maturity, importance, and acceptance by the community. However, the final decision will not be made until Sun's chief architect of Java SE, Danny Coward, submits the Java SE 7 platform JSR and an expert group forms. All Java library and language changes will be approved as part of this platform JSR, which will link together existing JSRs to form the full feature set. The current target for Java SE 7 is early 2010. We can expect a platform JSR to arrive in the first quarter of 2009.

The remainder of this article focuses on the features I believe are most likely to be included in Java SE 7, with code samples to demonstrate related changes to how we code today. All of the JSRs I'll discuss here have specifications and working prototypes and so are reasonably mature.

Better dependency management

For a long time now, Java developers (indeed all developers) have struggled with managing the dependencies within an ever-growing set of open source and commercial libraries. A typical enterprise application today relies on dozens of external JAR files and can itself comprise dozens of smaller internal projects worked on by different teams. We continue to search for better ways to manage this ever-increasing tangle of dependencies to make our builds repeatable and our deployments sane. The rise of dependency-handling build systems such as Maven and runtime deployment systems such as OSGi reflect this trend.

Early in the Java SE 7 cycle, two important JSRs attempting to tackle dependency management progressed: JSR 294: Improved Modularity Support in the Java Programming Language and JSR 277: Java Module System. Both focused on the development and deployment aspects, respectively, of the notion of Java modules. A module is a set of interrelated classes usually serving some common purpose, similar to a JAR that would commonly be produced by an open source project or an internal project managed in an IDE. However, a module's scope could potentially be a portion of a JAR or a set of several JARs, depending on development and deployment needs. In mid-2008, JSR 294 was simplified and merged into JSR 277 so that the same expert group could work on the two aspects in tandem.

In December 2008, Sun overhauled this plan yet again, announcing that Java SE 7 will focus solely on modularizing the JDK as Project Jigsaw in the OpenJDK. JSR 277 and the Java Module System will be put on hold until after Java SE 7. JSR 294 will be resurrected for the purpose of modularizing the JDK. Sun has stated its intention to work closely with the OSGi Alliance so that JSR 294 modules can be used by OSGi.

Information is still emerging about this new day for Java modularity, and it's a little early to parse the current wave of announcements for what they will actually mean to Java SE 7. Sun seems to set the minimum bar as breaking the JDK itself into modules and supporting those modules in the Sun virtual machine directly (but not as part of a new platform standard).

Project Jigsaw and the 'module' keyword

One question that begs an answer in Java SE 7 is how Sun will deal with the module keyword, a cornerstone of the original JSR 294 that is expected to be included in the upcoming platform release.

Consider a fictitious project named Flapjack made up of several packages. The project comprises a public API in the base package and several internal packages that implement the API:

  • org.flapjack - public API classes
  • org.flapjack.impl - implementation classes
  • org.flapjack.util - utility classes

In Java SE 6, if you need to place a factory class in the base package for instantiating instances of the API in the internal implementation packages, you must make the implementation classes public so they can be seen from the API package. There's no visibility level that would allow the API factory to instantiate the class without also allowing external classes to implement it directly, because they cross package boundaries.

JSR 294 modules would allow you to declare the whole set of packages as a module. You do this with a new declaration in the source code:

module org.flapjack;

You can add this new declaration to every source file in your project, or to a package-info.java file to apply it to an entire package at once. Although module is a new keyword, it is a "restricted" keyword that is treated as a keyword only where it is expected; thus, it can be used as a normal Java identifier everywhere else. This extends the language while maintaining backward compatibility.

In addition to the new declaration, you can also use the module keyword as a new visibility modifier that you place on a class to declare that the class is visible only to other classes within the same module. Listing 1 demonstrates this use of the module keyword.

Listing 1. Using module as a visibility modifier

module org.flapjack;
package org.flapjack.impl;
import org.flapjack.Flapjack;
module class FlapjackImpl implements Flapjack {
}

And finally, you can define a new module-info.java pseudo-class to annotate the module with metadata such as its version, main class (for execution), imported modules for dependencies, exported resources, and many other predefined or custom module annotations. Note that like the existing package-info.java file, the new module-info.java file uses an invalid Java source file name to avoid possible clashes with preexisting files.

At compile-time, JSR 294 has you compile your classes with javac (which now knows about modules and module-info.java files). How Project Jigsaw will specify the composition, loading, and verification of modules in the JVM remains to be seen.

(More) NIO APIs

JSR 203: NIO 2 extends and completes the work started in JDK 1.4 in the original NIO enhancements. The most obvious addition in NIO 2 is a complete overhaul of the file-access APIs. Most developers have used java.io.File and are aware of the long list of shortcomings:

  • No support for symbolic links
  • No support for straightforward or atomic move and copy operations
  • Cumbersome APIs for walking and filtering directories
  • Very limited support for access to permissions and file attributes
  • No API for watching directories or files
  • Limited error-handling capabilities (reliance on ignorable return flags and generic IOExceptions)

Fortunately, JSR 203 improves in all of these areas and more. The API is designed to be extensible from the start, supporting the idea of pluggable FileSystems in addition to the default FileSystem, flexible option sets for actions like opening and copying files, and system-dependent attribute definitions.

Listing 2 shows an example of how JSR 203 can be used for some common operations. Path is at the core of the API; you can think of it as the new File.

Listing 2. Some uses for JSR 203

import java.nio.file.*;

// FileSystems -> FileSystem -> Path
FileSystem fileSystem = FileSystems.getDefault();
Path homeDir = fileSystem.getPath("/Users/lskywalker");

// Shortcut with Paths helper class
Path homeDir = Paths.get("/Users/lskywalker");
Path secrets = homeDir.resolve("secrets.txt");
    
// Steal secrets
secrets.moveTo(Paths.get("/Users/dvader/secrets.txt"));


Beyond the filesystem APIs, JSR 203 completes many of the APIs started in the first incarnation of NIO, providing more support for multicast and a new set of APIs for asynchronous IO on files and sockets.

Tackling the time dimension

The Java Date and Calendar classes have long been in need of an overhaul. JSR 310: Date and Time API aims to do just that with a whole new library tackling the treacherous dimension of time.

JSR 310 provides support for both "continuous" time and "human-scale" time. The continuous time scale defines time as a series of discrete ticks at nanosecond resolution. The API defines an Instant as one point in time, and an Interval as the time from one Instant to another (including both open and closed intervals). Also, a Duration is some length of continuous time that is not tied to any particular Instant.

Listing 3 shows some continuous-time examples.

Listing 3. Continuous time

// Create some instants in seconds
Instant start2008 = Instant.instant(1199167200);
Instant start2009 = Instant.instant(1230789600);
assert start2008.isBefore(start2009);

// Create an interval - [inclusive, exclusive] by default
InstantInterval year2008 = InstantInterval.between(start2008, start2009);
assert year2008.contains(start2008);
assert ! year2008.contains(start2009);

// Create a duration in seconds
Duration minute = Duration.duration(60);
Duration hour = minute.multipliedBy(60);
Duration duration2008 = Duration.durationBetween(start2008, start2009);


For human-scale time, JSR 310 defines a series of classes with increasing information. The lowest level is LocalDate (only a date such as July 21, 1969), LocalTime (only a time such as 6:00:00), and a LocalDateTime, which combines the two. The Local classes are not tied to any particular time zone or any particular Instant on the continuous timeline.

OffsetDateTime adds precision by specifying a time-zone offset from universal time (UTC), which specifies a point on the continuous timeline, but it does not allow you to reason about time-zone rules, which are primarily based on government and political decisions. Finally, ZonedDateTime ties an offset to a particular time zone, allowing you to reason about Daylight Saving Time and other locale-specific time-zone matters.

Clock is a facade for accessing current moments in both continuous and human time scales. One nice feature is that Clock is defined as an abstract class with a factory method for obtaining the system Clock. However, because it's abstract, you can define your own subclass Clock implementation and either access time in some other source or have more control over it for testing.

Listing 4 shows an example of using the human-scale date and time classes.

Listing 4. Using human-scale time and Clock

// Local human-scale (not tied to TimeZone or Instant)
LocalDate dDay = LocalDate.date(1944, MonthOfYear.June, 6);
LocalTime quittingTime = LocalTime.time(17, 0);
LocalDateTime start2008 = LocalDateTime.dateTime(2008, MonthOfYear.JANUARY, 1, 0, 0, 0);

// Tie to time zone offset of -6 hours from UTC
OffsetDateTime start2008Offset = OffsetDateTime.dateTime(start2008, ZoneOffset.zoneOffset(-6));

// Tie to current local time zone
ZonedDateTime start2008Zoned = ZonedDateTime.dateTime(start2008, Clock.system().timeZone());

Finally, JSR 310 is built to interoperate with the older Date and Calendar classes, and it has full support for parsing, formatting, time-zone rules, and more.

Parallel processing

JSR 166y is a maintenance revision of the JSR that brought us all the java.util.concurrent goodies in J2SE 5.0 and updates in Java SE 6. The major addition in JSR 166y is a new parallel-processing package called fork/join. In particular, fork/join provides support for working on divide-and-conquer style algorithms that break up work recursively until it's small enough to do sequentially. Fork/join is ultimately implemented with a set of work queues and a technique known as work stealing, which allows idle workers to steal work from other queues. The core of the fork/join library is a new class called ForkJoinPool (effectively a thread pool) and a set of task types for decomposing problems.

Most typical applications don't have much use for a framework for solving computation-intensive divide-and-conquer algorithms. However, JSR 166y also provides a new functional-style API for working in parallel on arrays. A ParallelArray is a set of your domain items whose work is backed by a ForkJoinPool. You can define many common functional operators -- such as filter, map, and apply -- and apply them to a ParallelArray. The real benefit is that these operations execute in parallel via the ForkJoinPool and can automatically take advantage of increasing processor-core counts in the future without modifying the functions. It is still under consideration whether the ParallelArray will be included as part of the JDK in Java SE 7 or whether it will be released as an external library.

Listing 5 shows an example of how you can manage your vast collection of donuts with a ParallelArray.

1 2 Page
Join the discussion
Be the first to comment on this article. Our Commenting Policies
See more