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.

Listing 5. Using a ParallelArray

// Instantiate the ForkJoinPool with a concurrency level
ForkJoinPool fj = new ForkJoinPool(16); 
Donut[] data = ...
ParallelArray<Donut> donuts = new ParallelArray(fj, data);

// Filter
Ops.Predicate<Donut> hasSprinkles = new Ops.Predicate<Donut>() { 
  public boolean op(Donut donut) {
    return donut.hasSprinkles();
  }
};

// Map from Donut -> Integer 
Ops.Predicate<Donut> daysOld = new Ops.ObjectToInt<Donut>() {
  public int op(Donut donut) { 
    return donut.age(); 
  }
};

SummaryStatistics<Integer> summary = 
  orders.withFilter(hasSprinkles)
        .withMapping(daysOld)
        .summary();

System.out.println("with sprinkles: " + summary.size());
System.out.println("avg age: " + summary.average());


The concurrency utilities introduced in J2SE 5.0 and enhanced in Java SE 6 provide a firm base for writing concurrent applications on the 4- to 8-core machines common in our server racks today. The fork/join library takes us a bit further in making our logic parallelizable and scalable for a larger number of cores, such as the 16- to 32-core machines we'll be deploying to for the next couple years. This will give us some runway but in no way "solves" the problem of concurrency. Everyone in the industry is searching for ways to leverage the multicore world we now live in. Although Java has a head-start on this trend, shared-state concurrency is unlikely to be sufficient a decade from now. Fork/join is just another step on the journey.

Better precision through annotations

J2SE 5.0 brought us the world of Java annotations, which is still picking up steam as an alternative to external XML configuration metadata. In Java SE 6, annotations can occur only on class, method, field, and variable declarations. JSR 308: Annotations on Java Types allows annotations to occur anywhere types can occur, opening the possibility of more expressive and precise type systems.

The JSR does not itself define any additional annotations, although it opens the door for annotations such as those defined in JSR 305: Annotations for Software Defect Detection. The goal of JSR 305 annotations is to allow developers to define the semantics of method calls more precisely, such as whether nulls are allowed, whether collections can be empty, and so on.

Listing 6 shows some examples of how new annotations might be used.

Listing 6. Using annotations for greater precision

// A more precise class definition:
class UnmodifiableList<T> implements @Readonly List<@Readonly T> { ... }

// A more precise variable declaration:
List<String> str = new @NonEmpty @Readonly ArrayList<String>(stringSet);

Annotation processors can be plugged into the compiler to verify these annotations at compile time. This allows a great deal more specificity and precision, but it comes with a heavy cost of verbosity and will certainly fill some Java users with dread.

Simplifying Swing

A trio of Swing-related JSRs are in the works. JSR 296: Swing Application Framework provides a framework and functionality needed by most Swing applications to simplify development. Specifically, it provides:

  • A well-defined life cycle for the application
  • Injection of resources (such as labels, fonts, and colors)
  • Action management (including support for background tasks)
  • Persistent session information such as window placement

JSR 296 seems to have been in limbo ever since the departure in 2008 of the specification lead. There have been hints of revival, but many are questioning whether this effort will be resuscitated in time for Java SE 7.

JSR 295: Beans Binding and JSR 303: Bean Validation are targeted at solving problems prevalent in Swing applications but can also be used in non-Swing use cases as well. JSR 295 addresses the need to bind together fields in two (or more) objects. Properties can be bound in either one direction or both, and extensions exist to support common Swing models such as lists and tables. JSR 303 is a framework to create validators for fields and classes. The JSR defines a set of meta-annotations as well as a common set of constraint annotations.

Java Management Extensions (JMX) updates

JSR 255: JMX 2.0 is a comprehensive update to the JMX specification, taking full advantage of language features introduced in J2SE 5.0 and adding new important features including namespaces, federation of remote JMX servers, a new event service, a query language, and more.

And JSR 262: Web Services Connector for JMX allows clients to connect over Web services to a JMX MBean (which of course works for non-Java Web service clients).

Language changes

Given the limited remaining timeframe for Java SE 7 and the seeming reluctance to add major new language features, it is expected that only small changes will be included in the Java SE 7 platform specification. Joseph Darcy will be leading an OpenJDK project to collect and evaluate these language changes.

Closures are the biggest language feature proposed for Java SE 7. Closures would certainly have the greatest impact on the language, as well as the other JSRs I've discussed here. A number of proposals have been put forth, and the three most popular proposals have working prototypes. In particular, Neal Gafter's work on the BGGA closures proposal includes a complete spec and a working implementation, and it's the most thoroughly vetted of the existing proposals.

Given shrinking resources at Sun, the number of significant JSRs, and pressure to release, it seems that it's unlikely that closures will be included in the Java SE 7 release. That's a shame, in my opinion, because closures could simplify parts of the API in the NIO 2, fork/join, and other libraries. Without closures in Java SE 7, those opportunities will be lost.

Some possible smaller language enhancements include:

  • Strings can be used in the case clause of a switch.
  • Comparison operators (<, >, and so on) work directly with enum constants.
  • Chained invocation - void methods implicitly return this, allowing method chaining.
  • Extension methods - Statically imported methods can be called as if they were object methods, allowing APIs to be extended after the fact with static utility classes.
  • Improved catch of multiple exception types at once and subsequent rethrow of just those specific types.

Dynamic-language support

JSR 292: Supporting Dynamically Typed Languages on the Java Platform was started to introduce a new JVM bytecode, called invokedynamic, for better support of dynamic languages. John Rose has subsequently used the JSR as a forum to explore a number of possible JVM enhancements that could help languages other than Java on the JVM.

This work culminated in the first JVM Language Summit, held in September 2008, where features such as tail call optimization and interface injection were discussed. For functional languages that make heavy use of recursion, tail call optimization is important to avoid running out of stack space. Scala addresses this in the compiler itself. Clojure has language support for simulated tail calls and recently added language support for trampolining to support mutual recursion. If tail call optimization can be added to the JVM, Scala and Clojure could simplify or remove these features.

Mark Reinhold stated at the JVM Language Summit that JSR 292 will be included in Java SE 7. It is unclear at this point whether any features beyond invokedynamic will be included under JSR 292.

Java SE 7 and the future of Java

I believe we will see a Java SE 7 platform JSR in 2009 that will include most of the JSRs described in this article, but few if any changes to the language itself. It will be a stretch to integrate all of this work into the OpenJDK builds and release Java SE 7 in early 2010, as now planned.

Some question whether Java SE 7 is still relevant and whether anyone will even use it. Java continues to be one of the more important languages in use today, even given the rise of alternative JVM-based languages. Java has such a huge installed base that it will take generations of programmers before it stops being relevant. JSRs like 294, 310, and 203 seek to update core APIs with changes the are compelling to enterprise software developers. The forward march into the multicore era will make JSR 166 and JVM performance improvements compelling as well.

I believe widespread adoption of Java SE 7 will be slow but steady. Assuming the platform is released in early 2010, it will probably be 2011 before the new release gains a significant portion of market share. We've seen the same slow, steady progression happening with Java SE 6. J2SE 1.4 entered the End of Service Lifecycle in November 2008, and J2SE 5.0 will join it in late 2009. By that point, most businesses that do Java-based development will be looking at or deploying on Java SE 6. If Java SE 7 language changes are minimal, as currently indicated, many businesses could skip from J2SE 5.0 straight to Java SE 7.

Alex Miller is a Tech Lead at Terracotta Inc, the makers of the open-source Java clustering product Terracotta. Previously, Alex worked at BEA Systems on the AquaLogic product line and was Chief Architect at MetaMatrix. Alex blogs at http://tech.puredanger.com and speaks at user groups, conferences, and the No Fluff Just Stuff tour. He has an enduring love for his wife and three children, music, and nachos.

Learn more about this topic

More from JavaWorld

Join the discussion
Be the first to comment on this article. Our Commenting Policies