The major new feature in JDK 9 is the modularization of the core platform implemented by project Jigsaw. But because there are numerous other new features being included, let’s look at nine of those.
Caveat Emptor: Because JDK 9 has not yet been released and the Java SE 9 specification has not been finalized, some of these features may change from the description here to what’s in the final release.
1. The Java Shell (Read-Eval-Process Loop, REPL)
JDK 9 includes a new tool, jshell, which allows Java declarations, statements, and expressions to be evaluated. Unlike an IDE, where code must be edited, compiled, and then run, jshell works interactively. Developers can quickly prototype sections of code as jshell continually reads user input, evaluates the input, and prints the value of the input or a description of the state change the input caused.
To make the tool easier to use, it also includes features like a history with editing, tab-completion, automatic addition of needed terminal semicolons, and configurable predefined imports and definitions. Frequently, terminating semi-colons are not required. Many other modern languages already support this form of REPL development.
2. New Stream Sources
It’s always useful to be able to create a stream source from a collection of data, and JDK 8 provided a number of these outside the collections API (BufferedReader.lines() for example). Several new sources are being added in JDK 9 such as java.util.Scanner and java.util.regex.Matcher. Even Optional now has a stream() method that returns a stream of zero or one elements.
3. New Stream Features
There are four new methods in the Stream interface coming in JDK 9.
Firstly there are two new related methods: takeWhile(Predicate) and dropWhile(Predicate). These methods are complementary to the existing limit() and skip() methods but use a Predicate rather than a fixed value. The takeWhile() method will continue to take elements from the input stream and pass them to the output stream until the test method of the Predicate returns true. The dropWhile() method does the exact opposite in that it drops elements on the input stream until the test method of the Predicate returns true. All remaining elements in the input stream will then be passed to the output stream.
One thing to be careful of when using either of these methods is when you have an unordered stream. Since the predicate only needs to be satisfied once to change the state of elements being passed to the output, you may get elements in the stream you don’t expect.
The third new feature is ofNullable(T t). This returns a stream of zero or one elements depending on whether the value passed is null or not. This can be very useful to eliminate a null check before constructing a stream and is similar in a sense to the new stream() method in the Optional class.
The last new stream feature is an overloaded version of the static iterate() method. The version in JDK 8 took one parameter as the seed and created an infinite stream as output. In JDK 9, there is a now version that takes three parameters. This effectively gives you the ability to replicate the standard for loop syntax as a stream, e.g. Stream.iterate(0, i -> i < 5, i -> i + 1) will give you a stream of Integers from 0 to 4.
4. Parallel Support for Files.lines()
JDK 8 added a lines() method to the Files utility class that reads all lines from a file as a Stream. This read the file sequentially, so it was not possible to improve the efficiency of other parts of a stream by making the stream parallel. In JDK 9, if the Stream is parallel, the lines() method will map the file into memory and assign regions of the file to each thread processing the stream. Line breaks are used to divide the file so regions may not be exactly equal in size.
5. G1 Collector Used By Default
The G1 collector was first made available in JDK 7u4 but has been in development for some time before that. In JDK 9, it will replace the parallel collector by default. Some of the stated advantages of the G1 collector are the ability to efficiently use heaps in excess of 6Gb and allow concurrent compaction of the heap. This is achieved by dividing each generation of the heap into fixed size regions rather than treating them as contiguous areas of memory.
Regions can be analyzed and sorted based on the occupancy level of live data. Frequently at garbage collection, regions will no longer contain any live data, and these can be made available for reallocation without any further work. Using the sorted list, compaction of data can be made more efficient by collecting live objects from low occupancy regions into a smaller number of regions.
G1 will still fallback to a full stop-the-world compacting collection if it cannot keep up with the rate of allocation. In contrast, the C4 collector used in Azul’s Zing JVM does not require stop-the-world pauses that are proportional to heap space and can support heaps of up to 2Tb for latency sensitive applications.
6. Spin-Wait Hints
This is a small change in that it is only one method, but being added to the Thread class is a pretty big deal. The other significant aspect of this feature is that it is the first JDK Enhancement Proposal (JEP) to be included that was proposed by a company other than Oracle (in this case, Azul Systems, whom I am lucky enough to work for).
The onSpinWait() method allows application code to hint to the JVM that it is currently in a spin loop. If the JVM and hardware platform support optimizations when spinning, these can be used, otherwise, the call is ignored. Typical optimizations include reducing thread-to-thread latencies and reducing power consumption.
7. Search Capability in the Standard Javadocs
In some ways, this is my favorite new feature in JDK 9. I’m sure we’re all familiar with the traditional HTML style of API documentation provided: One window for packages, one for what’s in the package, and one big window for details of a package, class, or interface. The look of this was updated some time ago using CSS to give it a slightly more modern look and feel, but beyond that, we’re still firmly in the mid-1990s. Now, however, there is a search box included in the top right-hand corner! This makes life so much easier when you know which class or method you’re looking for and want to access it quickly without excessive scrolling, clicking, or both.
8. Enhanced Deprecation
Deprecation was introduced in JDK 1.1 with the idea of letting developers know when they were using APIs that might be removed at some point int the future. Initially, items were marked as deprecated using a javadoc tag, @deprecated. In JDK 5.0, with the introduction of annotations, deprecation was extended to include a @Deprecated annotation as well.
JDK 9 will enhance the @Deprecated annotation to provide better information about the status and intended future of APIs. Primarily, this will mean support for two new methods:
- forRemoval(): This returns a boolean to indicate whether this API element is intended for removal in some future release.
- Since(): This returns the release or version number, as a string, when this API element was first marked as deprecated.
There are a number of APIs that will potentially be marked as deprecated in JDK 9. An up-to-date list can be found in JEP 277.
9. Private Methods in Interfaces
Interfaces changed in a big way in JDK 8. Firstly, there was the introduction of default methods. This allowed new methods to be added to existing interfaces without forcing a break in backwards compatibility. Because this meant that behavior could be included in an interface (giving Java multiple-inheritance of behavior for the first time) it was also logical to include static methods. In JDK 9, the introduction of private methods in interfaces will allow common code to be extracted to methods that will remain encapsulated within the interface.
Although JDK 9 will not contain quite such exciting features as Lambda expressions and the Streams API of JDK 8, I hope this list has shown that there are some very useful new things outside of project Jigsaw coming to the JDK.