search
Java 9 is out: Features at a glance

New Java 9 features at a glance

Henning Schwentner
Java 9

© Shutterstock / koya979

We’ve been waiting for this moment for the past 3+ years but now it’s finally here — Java 9 has been released. In this article, Henning Schwentner presents the new version’s features.

New modular system: Project Jigsaw in Java 9

With version 8, Java did get a lot of new features, of which the support of Lambdas had certainly the biggest impact. Also, the enabled bulk operations on collections and the new date-time API improved the daily life of the Java developer. However, a feature that has been wanted for a long time has not made it into Java 8 and became the trademark of the freshly released Java 9 version — the modularization with Project Jigsaw.

Project Jigsaw addresses two problems that have hitherto affected Java, namely the “JAR hell” and the lack of a strong encapsulation mechanism above classes. From the beginning, Java had a package construct. A class can have one of two visibility levels within a package. Either it is public, in this case, the class can be accessed from anywhere. If it is not public, it can only be accessed from within the package.

But packages cannot be nested. As a result, you either have unstructured „big ball of mud“— packages or those that consist only of public classes. JARs (Java Archives) are just a set of public class files plus data. They are not components and do not offer encapsulation. Therefore, they do not have an interface, or rather, the interface of a JAR is all that the JAR contains because it can’t hide anything from outside access due to a lack of encapsulation.

Version 9 gives Java the possibility to define modules. A module is a named, self-describing program component that consists of one or more packages (and data). Modules can be defined as in Listing 1.

module de.module.a {
  exports de.module.a.paket.x;
}
module de.module.b {
  exports de.module.a.paket.y;
  exports de.module.a.paket.z;
}
module de.module.c {
  requires de.module.a;
  requires de.module.b;
}

This interface definition indicates which packages a module offers to the outside world (with the keyword exports), and which modules it requires from the outside (with the keyword requires). Attention: This is not a typo in the previous sentence; a module exports packages, but requires modules. This can be confusing at first glance since packages and modules have the same or very similar names by convention. All packages of a module that are not explicitly exported can only be used within the module. If you try to access them from outside the module, a compiler error occurs.

Using Modular JARs as Modules

Now that we have seen how to declare a module, let’s answer another question: where do we write the module declaration? The convention says that you declare it in a source code file called module-info.java, and place it at the root of the file hierarchy of the module. The compiler then translates this into the file module-info.class. The name “module-info” contains the hyphen on purpose because it is an invalid class name. This way, existing code will not be damaged. The Java file is then called module declaration and the class file module descriptor.

If you have a module declared in this way, it is possible to create a modular JAR from it. It is structured like a conventional JAR file, with the difference that it has a module-info.class file in its root directory. Such a modular JAR can be used as a module. For reasons of downward compatibility, it can also be used as a classic JAR file and in a classpath. Then the module-info.class is simply ignored. Speaking of classpath: With the introduction of the module concept, it is replaced by a modulepath. In the modulepath you can then specify where specific modules can be found in the file system.

In the past, there was a classpath with a bunch of JARs in disorder, which could use each other uncontrollably. What’s more, everything within the JARs could be accessed. Now we can use the module mechanism to clearly define which module should and can use which other modules. This makes it possible to use several versions of the same library parallel. For example, module A can use the library in version 1, module B in version 2 and finally, module C can use the two modules A and B.

Domain-driven design with Java 9

With the module concept, the architecture of software can be expressed much better. For example, layers can be represented as modules and their interfaces can be defined clearly. The compiler can at least partially detect and prevent architectural violations. Let’s take an example of a banking application, designed with domain-driven design (Listing 2 and Fig. 1).

 
module de.wps.bankprogramm.domainLayer {
  exports de.wps.bankprogramm.domainLayer.valueObject;
  exports de.wps.bankprogramm.domainLayer.entity;
}
module de.wps.bankprogramm.infrastructurelayer {
  exports de.wps.bankprogramm.infrastructureLayer.database;
}
module de.wps.bankprogramm.applicationLayer {
  requires de.wps.bankprogramm.infrastructureLayer;
  requires de.wps.bankprogramm.domainLayer;
  exports de.wps.bankprogramm.applicationLayer.repositories;
}
module de.wps.bankprogramm.uiLayer {
  requires de.wps.bankprogramm.domainLayer;
  requires de.wps.bankprogramm.applicationLayer;
}

The four layers of the system are implemented as modules. The module of the specialized logic layer (i. e. the module domainLayer) is declared in such a way that it has no dependencies to other modules. We don’t want to pollute our business code with dependencies on technical code. It contains a package for the entities of our system and one for its value objects. The repositories, in turn, can access the infrastructure layer (module infrastructureLayer). Therefore, in this design, they are plugged into the application layer module (applicationLayer). According to the above declaration, it may access the infrastructure and business logic layer.

The user interface layer (uiLayer module) can then access the user logic and application layer. Using the package with the database access code would result in a compiler error because it is in the infrastructure package and it was not specified in the requires of uiLayer. The assignment of repositories to the application layer is architecturally not completely clean but was done here in order to avoid making the example too complicated.

Cutting the JDK into pieces

The module mechanism is interesting for many projects, but especially for the JDK itself. This is where the name of the project, Jigsaw, comes from. And with this jigsaw Java should be divided into modules. Up to now, the entire JRE must always be delivered, even if only small programs are to run that do not have a GUI or do not access a database. With Java 9, JRE and JDK are broken down into modules themselves. This allows each program to define what it needs, reducing memory usage and improving performance.

Java standard modules include java.base, java.sql, java.desktop and java.xml. The basic module java.base is always implicitly included — just as the package java.lang does not need to be imported separately. The module java.base will contain the packages java.lang, java.math and java.io. For the modules of the JDK itself, JAR files are not sufficient, because they must also contain native code, for example. Therefore, the so-called JMOD files were introduced here. A direct quote of Mark Reinhold, chief architect of Java: “JMOD files are JAR files on steroids”. Project Jigsaw is certainly the big change that comes with Java 9, and it is also its key feature. But there are also a number of other features that will make the developer’s life easier.

What else happens in Java 9

Many programming languages have a read-eval-print loop (REPL), i. e. a kind of command line that directly executes code in this language and outputs the result. Java didn’t have something like this in the standard JDK. There are third-party products like BeanShell or Java REPL and a plug-in for IntelliJ IDEA. The Kulla project introduces the JShell to the JDK — the official REPL for Java. This offers hope that Java will be easier to learn. An interactive mode can give the programmer much faster feedback than the classic write/compile/execute cycle.

With Java 9, there is now the CLI program jshell for the command line. An API is also provided so that other applications can use this functionality. This is especially interesting for the IDE manufacturers, who want to use the JShell in Eclipse, NetBeans and Co. can be installed.

Unicode is supported

Unicode exists to encode the characters of different languages. The standard is constantly being extended, and Java is not yet supported for the last two releases 7.0 and 8.0. Unicode 7.0 contains improvements for bidirectional texts, i. e. those that contain sections in both Latin and non-Latin characters.

With version 8.0, for example, the emojis are extended by smileys in different skin colors and new faces like that of Mother Christmas. Furthermore, a separate JEP (No. 226) allows you to save property files in UTF-8. Only ISO 8859-1 was previously supported as encoding. The ResourceBundle API is extended for this purpose.

Creating Collections with ease

It is not too difficult to define several objects at once, using arrays.

String[] firstnames = { "Joe", "Bob", "Bill" };

Unfortunately, this is not so easy with Collections, yet. To create a small, unchangeable Collection, one must construct and assign it, subsequently add elements and finally build a surrounding wrapper.

List firsnamesList = new ArrayList<>();
firstnamesList.add("Joe");
firstnamesList.add("Bob");
firstnamesList.add("Bill");
firstnamesList = Collections.unmodifiableList(firstnamesList);

Instead of having one line of code, we have five lines at once. Furthermore, it cannot be expressed as a single expression. There are several alternatives, e.g. Arrays.asList(), but if you are to define plenty of values, it is going to take a long time:

Set firstnamesQuantity = Collections.unmodifiableSet(
 new HashSet(Arrays.asList("Joe", "Bob", "Bill")));

Java 9 thus introduces convenience methods, which make similar things easier to express.

List firsnamesList = List.of("Joe", "Bob", "Bill");

With varargs, it will be possible to transfer a different number of parameters to these factory methods. This functionality is offered for Set and List, or in a comparable form also for Map. Due to method implementations to interfaces in Java 8, the so-called default methods, it is possible to define those convenience methods directly within the interfaces of List, Set and Map.

HTTP/2 support in Java 9

HTTP, the protocol for transferring web pages, was adopted in its current version 1.1 as early as 1997. It was not until 2015 that the new version 2 became standard. The new versions aim is to reduce latency, to thus allow for faster loading of web pages. This is achieved through various techniques:

  • Header compression
  • Server-Push
  • Pipelining
  • Multiplexing of multiple HTTP requests across a TCP connection

At the same time, compatibility with HTTP 1.1 remains maintained. Large parts of the syntax even remain unchanged; for example, the methods (GET, PUT, POST and so on), the URI, status codes, and header fields.

Java will have out-of-the-box support for HTTP/2 with the implementation of JEP 110. In addition, the outdated HttpURLConnection-API is being replaced. It was created during the days of HTTP 1.0 and used a protocol-agnostic approach. This suited the nineties, as it was not yet certain how successful HTTP was going to be. Nowadays, however, support for e.g. Gopher, is less important. ALPN is also to be supported. In the New World, you can then use a contemporary Fluent-API.

HttpResponse response = HttpRequest
  .create(new URI("http://www.javamagazin.de")
  .body(noBody())
  .GET()
  .send();

The resulting HTTP response can then be used to query status code and content:

int statusCode = response.responseCode();
String body = response.body(asString());

Reduced memory consumption with compact strings

As of version 1, strings in Java are displayed using the class java.lang.String. From the beginning, this class contained an array of char. This data type occupies two bytes in Java. This makes it easy to display characters in UTF-16 and not just support the Latin alphabet. However, many applications only use characters from the Latin-1 encoding, which only requires one byte. In this case, every second byte is empty and wastes memory space.

JEP 254, therefore, introduces an implementation of the String class, which contains a byte array plus an encoding field instead of a char array. The encoding field specifies whether the string contains either a classical sequence of UTF-16 characters occupying two bytes each or a sequence of Latin-1 characters occupying only one byte each. The encoding in which the respective string is created should be recognized automatically by the strings content.

The pleasant thing with this optimization is that you automatically benefit from it. It is, in fact, a mere implementation detail, which maintains 100% compatibility with old Java versions. Applications which use many strings will thus significantly reduce their memory requirements – by simply installing the latest version of Java. In addition to the String class, related classes such as StringBuilder and StringBuffer, as well as the HotSpot VM, are adapted.

JavaDoc enhancements in Java 9

Until now, JavaDoc was only able to produce HTML in the outdated version of 4.01. With Java 9, it will be possible to create HTML5. Therefore, the command javadoc is to specify which version of HTML code to generate. The explicit non-goal of the associated JEP 224 is to abolish the three frames structure. Hopefully, this will be done with a future version. Furthermore, the generated HTML pages are to be provided with a search mechanism for searching for certain Java elements. The results are then categorized according to “Modules”, “Package” or “Types”.

Automatic scaling of HiDPI graphics

On the Mac, the JDK already supports retina displays, but on Linux and Windows, it does not. There, Java programs may look so small on current high-resolution screens, that they cannot be used. This is because pixels are used for size calculation on these systems – regardless of how large a pixel actually is. And the fun part of high-resolution displays is after all, that pixels are very small.

JEP 263 extends the JDK in such a way, that the size of pixels is also taken into account for Windows and Linux. For this purpose, more modern APIs are used than hitherto: Direct2D for Windows and GTK+ instead of Xlib for Linux. Graphics, windows, and text are thereby scaled automatically. JEP 251 also provides the ability to process multi-resolution images, i.e. files which contain the same image in different resolutions. Depending on the DPI metrics of the respective screen, the image is then used in the appropriate resolution.

What else comes in Java 9?

Like any other Java release, Java 9 contains a number of minor details and updates. These include:

  • The new ARM architecture AArch64, which raises ARM processors up into the 64-bit tier, is now being supported.
  • As of version 1.2, Java uses its own proprietary format for storing cryptographic keys: JKS. JEP 229 new introduces the standard file format PKCS12 in Java.
  • Update 40 of Java 8 introduced the Garbage Collector G1 (Garbage First). Java 9 now elevates G1 to standard garbage collector status.
  • Up to Java 8, the Image I/O Framework does not support the image format TIFF. This will be changed with JEP 262 and javax.imageio will be extended accordingly.
  • With Rhino, Java has a JavaScript execution environment. For IDEs and similar tools, JEP 236 releases the previously only internally available API of the parser publically, for accessing AST.

Prospects: What comes after Java 9?

Originally, this article was supposed to start with: “In September 2016, the new Java version 9 will be released”. The fact that it is now a whole year later is surely not too bad because many of the changes fall into the “housekeeping” category.

So, the current versions of the Unicode and HTTP standards are finally supported. There are also minor changes which make developer life easier, such as a more convenient creation of Collections and the implementation of compact strings.

The most important feature is clearly the module concept of Project Jigsaw. Major projects and those which are in need of a small memory footprint are a key factor, will benefit from this development. Major projects benefit because the problem of JAR-hell is on one hand solved with the ModulePath, and on the other hand because the architecture of these systems can be expressed more clearly with modules. Memory-sensitive projects benefit because the JDK itself is divided into modules, and no longer needs to be loaded in its entirety.

Another exciting topic is the prospect of what will come after Java 9. It seems as if Java 9 is the last version in the traditional version scheme. As for the future, Mark Reinhold has proposed to release a new release every six months and to name it the year and month of the release. The next step would be Java 18.3. In terms of content, the Valhalla project with value types is announced as the “Next Big Thing”.

But for now, we are happy about Java 9!

Author
Henning Schwentner

Henning Schwentner

All Posts by Henning Schwentner

Henning Schwentner loves programming. He lives this passion as a software architect and consultant at WPS - Workplace Solutions in Hamburg. His projects are agile and in programming languages such as Java and C#, but also ABAP. He is interested in the evolution of programming languages, long-lasting software architectures and major refactorings. Twitter: @hschwentner GitHub: hschwentner

Comments
comments powered by Disqus