Nuts and Bolts Java 9 Lead image: Lead Image © Krockenmitte, photocase.com
Lead Image © Krockenmitte, photocase.com
 

Finally: Java 9

Land Ho!

Java 9 tempts programmers with innovations intended to facilitate the development and operation of Java applications. By Carsten Zerbst

For a long time, Java [1] has easily topped the rankings of popular programming languages. This is not surprising; after all, programs developed in Java can be used anywhere from cellphones to mainframes and across all operating systems. However, a glimpse at the former shooting stars Perl and PHP shows that there is no guarantee of permanently riding atop the heap.

Regular updates help keep the language at the cutting edge and the estimated nine million Java programmers happy, but they have needed patience, because major release 9 has taken its time. Originally, it was planned as an interim release to deliver to the themes that were not ready in time for Java 8.1. "As quickly as possible" originally meant mid-2015, then mid-2016, and finally 2017. It remains to be seen whether the project schedule will be followed this time, although test builds are now available online [2].

Jigsawing

One core feature of Java 9 par excellence is the Java Platform Module System that became known as Project Jigsaw [3]. Thus far, the Java compiler and the run-time environment have thrown all available libraries from the class path into a large pot. Whether this turns out to be a tasty soup or smoke and mirrors partly depends on subtle changes in the class path.

Many developer hours have been spent in class path hell battling against the class loader. The problem is, only the right libraries and library versions in the appropriate order result in a working application. Approaches such as Maven, ServiceLoader or OSGI only partially mitigated the situation and had to take a wide detour around the standard libraries.

With Jigsaw, this should be different. The new modular system pervades the entire stack of the compiler, from the Java Runtime Environment (JRE) and the standard libraries to the application libraries. The development effort for Jigsaw was originally estimated to be about size XL, but in the real world, a number of Xs were added. The initial plans had their sights set on Java 7.1; ultimately, Jigsaw now first appears in Java 9. All three affected versions were delayed by years.

Totally Modular

The result is not only improved handling of libraries, but modularization also allows developers to tailor the JRE to the needs of an application. After all, the standard libraries in Java 8 weigh in at around 60MB and 20,000 classes. They not only need space on the hard drive, but the computer also needs to load them into memory at every startup and check the classes and methods they contain. Less powerful machines (industrial automation, IoT, network appliances) welcome every single megabyte saved, so the application uses less space and launches faster.

Java 9 dismantles the monolithic standard library modules. If you do not need features such as the CORBA stack, the JavaScript interpreter, or encrypted XML documents, you will soon have the opportunity to tailor the installation to your own needs for the first time.

A Scenario

The scenario shown in Figure 1 is used as an illustration of the new modular strategy. The sample application consists of two proprietary modules (modulea and app). Also on board are two modules from Java itself and another two for logging.

Module dependencies with Jigsaw in a sample scenario.
Figure 1: Module dependencies with Jigsaw in a sample scenario.

The modulea module includes everything related to the Customer business object. It contains a Customer interface, the matching CustomerService for searching and saving, and the associated implementation (Impl) classes. For this purpose, the software needs classes from the modules java.core, java.xml, and slf4j.core. The app module contains the application itself and requires modulea plus logback.core; the modules required in moda are implicitly available.

At the file level, modules are ordinary Java archives in JAR format that additionally contain a description of the module. They each provide module_info.java files that the developer compiles with the other classes and bundles into the JAR.

Listing 1 shows the module description for modulea. The declaration starts with the module keyword; the requires point to the code to the necessary modules. The compiler and the JRE use this to load the modules or to inform the user that they are missing immediately on startup. For modules like app to be able to use the two interfaces, the module description releases the contained package using export.

Listing 1: modulea description

01 module de.lm.java9.modulea {
02     // required
03     requires java.base;
04     requires java.xml;
05     requires slf4j.api;
06
07     // exported
08     exports de.lm.java9.modulea;
09
10     // provides a service implementation
11     provides de.lm.java9.modulea.CustomerService with de.lm.java9.modulea.intern.CustomerServiceImpl;
12 }

All other classes from modulea are not visible outside of the module. Although the CustomerImpl class is declared as public, the contained package cannot be reached outside of the module because of a missing export. In this way, developers could enforce loose coupling so that the user of a library sees its interfaces but has no access to the actual implementation or helper classes.

Ultimately, access to the object instances of the exported interfaces are needed somehow. Putting the CustomerService implementation in the public package would be contrary to the idea of loose coupling, because a user of the objects should not have to worry about how this is implemented. Here, the well-known but little-used ServiceLoader enters the scene as a solution. It can be used to query a CustomerService instance without knowing or accessing its implementation. Its application is shown in Listing 2, in which the main application queries CustomerService without knowing anything about the related implementation class.

Listing 2: ServiceLoader application

01 // Create the ServiceLoader for a CustomerService
02 ServiceLoader<CustomerService> sl
03         = ServiceLoader.load(CustomerService.class);
04
05 // Use first implementation
06 CustomerService service = sl.iterator().next();
07
08 set<Customer> customer = service.search("Tux*");

ServiceLoader thus acts as a broker between different modules. To do so, the providing module must publish the implementation using the provides keyword (Listing 1, line 11), and the module that is using it must publish it via uses (Listing 3, line 7).

Listing 3: app description

01 module de.lm.java9.app {
02     // required
03     requires de.lm.java9.modulea;
04     requires logback.core;
05     requires logback.classic;
06     // uses Service
07     uses de.lm.java9.modulea.CustomerService;
08 }

Java 9 breaks down the normal run-time library into 96 small modules, such as java.core and java.xml. It is comparatively easy to switch your own applications to the new module concept; libraries used for this purpose do not usually need to support it immediately. Instead, it is typically fine to add the normal JARs to the module path (e.g., slf4j or logback). They are then available as modules in automatic mode.

Normal visibility rules from the class definition apply (private, package, public). The module names each derive from the names of the JAR files. Through the use of these names, they can be used by real modules in named mode with a module description.

If you use dirty hacks like Class.forName or load resources across JARs, you will not be able to get your application running on Java 9 without making changes. This means moving to the new strategy, or at least building a bridging module that combines the old and new worlds.

All told, the wait for Jigsaw seems to have been worthwhile. For example, the dependencies and published interfaces can now be cleanly defined and evaluated throughout the entire life cycle, from compiling through run time. Developers can force loose coupling for the first time using the ServiceLoader mechanism and the different visibilities inside and outside a module.

The modular run-time environment itself allows for a smaller memory footprint on less powerful hardware. Class.forName also causes comparatively little pain. The downside is the lack of support for module versions as offered by Maven. The only escape route here is to manipulate the module name as in modulea_v1, modulea_v2, and so on.

Tools

Java 9 offers two new tools for working with modules: The first takes care of tasks relating to module dependencies. Among other things, it prepares them as texts or graphs or generates module descriptions for existing JAR files. The run-time environment can be trimmed with JLinker to match a module description. A minimal installation thus shrinks from 275MB (Java 8) to 40MB, reducing the startup time of a simple application on a PC by two-thirds, or about 0.9 seconds.

Thanks to the new -html5 option, the Javadoc tool now generates HTML with a more modern, barrier-free design and appearance. Not only a matter of a modified stylesheet, the generated Java documentation impresses with, among other things, a built-in search for class and method names and tooltips (Figure 2). The displayed classes can be restricted to selected Java modules, or you can view only the modules for a particular class.

Javadoc appears in a new guise in Java 9 thanks to the -html5 option.
Figure 2: Javadoc appears in a new guise in Java 9 thanks to the -html5 option.

Shell Factory

JShell, a more recent addition, allows the use of uncompiled Java as an interpreted language. The idea is not new: Patrick Niemeyer presented a first implementation 17 years ago in the form of BeanShell [4]. However, it never supported the full range of Java and work ground to a stop over the past few years. This situation was reason enough for the Java compiler group to begin work on a new shell code-named Kulla (the Sumero-Babylonian brick god). As a REPL (read, evaluate, print, loop) tool, it allows Java code to be executed line by line and is launched by typing jshell at the command line (Figure 3).

JShell evaluates entries after each newline, much like Python or TCL.
Figure 3: JShell evaluates entries after each newline, much like Python or TCL.

JShell evaluates the input after each newline, as in Python or TCL, whether it is normal Java code or one of the JShell commands. JShell commands all start with a slash; /help shows an overview of the available commands. When a line is executed, Java 9 either automatically creates variables, or the developer has to define them with a type and name. The /var command shows a list of defined variables and their values.

JShell accepts normal and static imports anywhere; /import lists those defined so far. Developers can use JShell not only to test small snippets of code like the DateTimeFormatter here, but it also supports the full syntax of Java 9, from a simple one-liner, through lambda expressions, to defining whole methods and classes.

Fortunately, programmers do not have to type flawlessly at the command line. If you mistype the code, a Java compiler error message appears, and you can retry. As in Bash, you can retrieve and edit previous input using the arrow keys. Expansion of class paths by pressing the Tab key works much the same way.

If you prefer working in a graphical editor, you can launch one by typing the /edit command (Figure 4) or load externally written code from a file with /o. Unlike compiled code, the semicolon at the end of the line is optional, and you don't have to worry about handling exceptions with try and catch blocks. More in-depth integration with the usual suspects (e.g., NetBeans, Eclipse, and IntelliJ) is expected in the next few months; IDEs for Python show what is possible in this direction.

From the new JShell, you can even launch a simple editor.
Figure 4: From the new JShell, you can even launch a simple editor.

Running

Work on the run-time library was also intended for Java 9, but there is not much of this left because of the delay. The most interesting new entry is the enhanced process API, which makes it possible, after years of waiting, not only to launch external processes, but also to stop them, access process IDs, and conveniently wait for them to end.

Swing was given some fine tuning. Instead of the obsolete GTK+ 2 library, the current GTK+ 3 library is now used, thus supporting settings for high-resolution displays.

The HTTP client has also seen the writing on the wall with HTTP/2 support. The frame-based protocol offers less overhead and lower latency and is now fully supported, thanks to the new HttpRequest and HttpResponse classes. The HttpRequest class is used to build a request, and the Fluent API lets programmers conveniently specify all the required information. Listing 4 shows an example that presents the results with HttpResponse.

Listing 4: HTTP/2 client

01 HttpResponse response = HttpRequest
02                 .create(new URI("http://www.linux-magazine.com"))
03                 .headers("User-Agent", "Java9")
04                 .GET()
05                 .response();
06
07 LOG.info("status : " + response.statusCode());
08
09 Map<String, List<String>> headers = response.headers().map();
10 for (String key : headers.keySet()) {
11     LOG.info(key + " : " + headers.get(key));
12 }
13
14 String body = response.body(asString());
15 LOG.info("body : " + body);

The question of which elements the Java developers would discard is almost more important than what has been added. To ensure backward compatibility, they have so far not removed a single class, method, or variable. Meanwhile, at least 60 classes and 400 methods are tagged as @deprecated; some of them have already been marked for removal in Java 1.1. After 20 years, Oracle finally has relented and announced that it will remove obsolete parts.

The most prominent victim is the Java applet, which breathes its last breath in Java 10. It provided good service, boosting the popularity of Java in the early years, but it is undesirable in the browser for security reasons, just like Flash or Silverlight. Ironically, the outgoing applet leaves the biggest gap in the area of creating certificates, encrypted data transfer, or signatures; HTML5 lacks equivalent capabilities.

The cleanup will take place in small steps; the first one has already been taken. The @deprecated annotation now comes with two optional attributes forRemoval and since, which mark the classes that will disappear in the future.

Summing Up

In addition to the points mentioned here, a number of changes are probably only relevant for a few developers, such as a Linux/s390x port from SAP and the Red Hat-contributed Linux/AAarch64 port for the 64-bit ARM platform. Unicode version 7 is now included instead of 6.2, and Java 9 can load TIFF images, support SHA-3, and more.

On the technical side, Java 9 has thus met with a warm reception; the changes have been extensively matched with the JDK enhancement process. Even 10 years after Sun released the source for Java, the development model still works quite well; participation by other companies is evidence enough. The coming months will show how long it takes for the essential libraries to become available as modules. The benefits are obvious.

Highly configurable libraries in particular use solutions that will no longer run with project Jigsaw. One can only hope that the permanent delays come to an end when Jigsaw is finally released. According to the release planning from 2014, Java 10 is supposed to be with us in 2017. The first plans for it have been drawn up, including the Valhalla [5] project to improve the type system and add speed. The currently unknown release date will keep programmers on the edge of their seats.