Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.

The best Java 9 Language and API improvements

WEBINAR ALERT! Join our latest ZTLive session: What’s New for Developers in JDK 9 featuring Simon Ritter and Dr. Venkat Subramaniam!


Java 9 collections factory methods

Hurray, the long awaited Java 9 release is right around the corner. It’s been a bumpy train ride, but it seems that all the discussions surrounding the module system are progressing and the majority will likely agree to it moving it further. So, we should assume it’s going to be released soon, most likely 21st September 2017.

In this post, I don’t want to spend time on discussing the module system in detail, but instead, I want to talk about what every Java developer can benefit from: the upcoming API and language changes.

So here’s a list of our favorite API changes in Java 9. Naturally, you can just look at the code examples in the post, to get the gist of what’s shown. But you can also fire up JShell and run these snippets as we talk about them to see for yourself what is going on. I’ll wait for you to start JShell up before continuing… ready? Not yet? Ok… done? Still not? Yeh, it takes a while to warm up… ok it’s started, great! Let’s begin.

Collections of factory methods

One of the most awaited changes in Java 9 are the collection literals for the easier definition of the common collections. Just kidding, of course, we’re talking about Java here, so there are no collection literals; these are static factory methods. Nonetheless, now you can easily define Lists, Maps, and Sets with the predefined elements.

jshell> List.of(1, 2, 3)
$1 ==> [1, 2, 3]
jshell> Set.of(1, 2)
$2 ==> [2, 1]
jshell> Map.of("hello", "world")
$3 ==> {hello=world}

The static methods in the interfaces make it possible and the List, Set, and Map interfaces are enhanced to have the method for collection creation with up to 10 elements.

The resulting objects are immutable collections that are optimised for performance. For example, a singleton list, with just 1 element holds the item in a field to speed up accessing the value.

jshell> List.of(1).getClass()
$4 ==> class java.util.ImmutableCollections$List1


A couple of very welcome additions to Java 9 have been updates to the existing Streams API. In particular, the dropWhile and takeWhile methods. These behave quite predictably: dropWhile discards the first items of the stream until a condition is met, takeWhile processes items until a condition is met.

jshell> IntStream.range(1, 10).dropWhile(x -> x < 5).forEach(System.out::println)

Another welcome addition is the iterate() method. Iterate allows you to write proper replacements for the for loops using streams. It takes the initial value of the stream, the condition that defines when to stop iterating and the step function to produce the next element.

jshell> IntStream.iterate(0, x -> x < 3, x -> x + 1).forEach(System.out::println)

If you ever wanted to calculate fixed points of the functions using Java 8 streams, your wish has come true in Java 9.


Let’s talk about Optionals. If you want to refresh your memory on them, we have a helpful cheat sheet on Java 8 best practices that contains a section about them. One method added to Java 9 Optional is the long-awaited or(). The or() method gives you a fluent way of chaining behaviour on Optionals without checking if the value is present or not.

public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
jshell> Optional.empty().or(() -> Optional.of("RebelLabs"))
$5 ==> Optional[RebelLabs]

Another welcome addition is the ability to convert an Optional into a Stream containing at most one element. It’s really useful if you want to use the laziness of the Streams API. Check out the difference in the examples below. Calling map() on the Optional executes the mapping function immediately, on the Stream — not.

jshell> Optional.of(1).map(x -> x * 3)
$10 ==> Optional[3]
jshell> Optional.of(1).stream().map(x -> x * 3)
$11 ==>$3@67b92f0a

The last, but by no means least, Optional addition we want to talk about is the ifPresentOrElse method. In Java 8, you could specify the behaviour you want to execute if the value in an Optional is present. In Java 9 you can pass 2 Runnables to specify what to do if the value is present and otherwise.

jshell> Optional.empty().ifPresentOrElse(x -> System.out.println(x), () -> System.out.println("empty"));

Completable futures

Another piece of the API that got a makeover is the CompletableFuture class. There are a couple of interesting additions that make coding correct and beautiful concurrently in Java easier.

One of the things that excited us the most is the copy() method that returns an immutable copy of an existing CompletableFuture. In the code snippet below we construct a CompletableFuture, make a copy of it and show that completing the copy doesn’t influence the original future object. This is incredibly useful when you offer an asynchronous API that returns CompletableFutures. Before you had to jump through hoops to avoid situations where clients can complete the future you returned. Now it’s a matter of calling the copy() method.

jshell> CompletableFuture<String> future = new CompletableFuture<>()
future ==> java.util.concurrent.CompletableFuture@35d176f7[Not completed]
jshell> future.copy()
$15 ==> java.util.concurrent.CompletableFuture@4973813a[Not completed]
jshell> future.isDone()
$17 ==> false
jshell> $15.isDone()
$18 ==> false
jshell> $15.complete("JRebel")
$19 ==> true
jshell> $15.isDone()
$20 ==> true
jshell> future.isDone()
$21 ==> false

The best bit is that the completion value propagates successfully in the normal way. Completing a future will complete all the copies.

jshell> CompletableFuture<String> future = new CompletableFuture<>()
future ==> java.util.concurrent.CompletableFuture@4bbfb90a[Not completed]
jshell> future.copy()
$24 ==> java.util.concurrent.CompletableFuture@5a8806ef[Not completed]
jshell> future.complete("XRebel")
$25 ==> true
jshell> $24.isDone()
$26 ==> true

Java 9 also delivers timeouts to the CompletableFutures. Dealing with an asynchronous API without a built-in way of specifying a timeout is messy. In Java 9, you can define exactly how you want to complete the future after a user-defined period of time.

jshell> CompletableFuture<String> future = new CompletableFuture<>()
future ==> java.util.concurrent.CompletableFuture@67205a84[Not completed]
jshell> future.completeOnTimeout("Isn't this amazing", 1, TimeUnit.SECONDS)
$28 ==> java.util.concurrent.CompletableFuture@67205a84[Not completed, 1 dependents]
jshell> future.isDone()
$29 ==> true

Process management API

Process management up to Java 9 was one of the things that weren’t as portable as Java developers would like to believe. Indeed, dealing with subprocesses in different operating systems was quite cumbersome. In Java 9 it’s quite straightforward. Java 9 adds the ProcessHandle class, which offers an API to inspect the current process, processes found by their PID, their children processes and so on. Check out the snippet below.

jshell> ProcessHandle current = ProcessHandle.current();
current ==> 6349
$33 ==> 6349
arguments()          command()            commandLine()        equals(              getClass()
hashCode()           notify()             notifyAll()          startInstant()       toString()
totalCpuDuration()   user()               wait(
$34 ==> Optional[/Library/Java/JavaVirtualMachines/jdk-9.jdk/Contents/Home/bin/java]

Accessing the command line used to start the process and its arguments would probably be the most frequently used part of this API, but other additions are no less interesting.

Another very common task that will be easier with Java 9 is executing code when a certain process finishes. Java 9 adds

CompletableFuture<Process> onExit()

method exactly to specify what to do when a process is finished. No more tears and third party libs required.


Rejoice exception haters, now you’ll have a new way of accessing the stack traces without creating the exception objects. Welcome the StackWalker.

StackWalker enables you to walk, filter and otherwise access stack traces in a very efficient manner. Check out the code snippet below that accesses the top 5 stack trace elements:

jshell> StackWalker.getInstance().walk(s -> s.limit(5).collect(Collectors.toList()));
$36 ==> [do_it$(java:36), jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(, jdk.jshell/jdk.jshell.execution.RemoteExecutionControl.invoke(, jdk.jshell/jdk.jshell.execution.DirectExecutionControl.invoke(, jdk.jshell/jdk.jshell.execution.ExecutionControlForwarder.processCommand(]

Hopefully, we’ll see less code creating exceptions for the stack going forward.

Language improvements

On top of the API changes, the language has evolved too. First of all ‘_’ (the underscore) is no longer a valid identifier. If you used to use it, you’ll now have to use the double underscore instead. (Hint: Don’t do that)

jshell> int _ = 1
|  Error:
|  as of release 9, '_' is a keyword, and may not be used as an identifier
|  int _ = 1
|      ^
|  Error:
|  reached end of file while parsing
|  int _ = 1
|           ^
jshell> int __ = 1;
__ ==> 1

The reason for that is that in the future, the underscore will possibly be used for the function parameters you don’t care about.

Interfaces also got a revamp. In Java 9 interfaces can contain private methods. The default methods in interfaces made Java 8 interfaces able to contain the common functionality. Now you can also use private methods to extract common functionality from inside an interface without creating utility classes.

Here’s a somewhat synthetic example:

jshell> interface A { private int zero() { return 0;} default int one() { return zero() + 1;}}
|  created interface A

The last addition we want to talk about is using the effectively final variables in the try-with-resources blocks. It simplifies the code, you don’t need to declare the variable in the try statement. You can just use the variables that are effectively final and just reference them in the try block.

boolean a() throws Exception { 
  Socket s = new Socket(); 
  try (s) { } 
  return s.isClosed();

After the try block is executed the referenced AutoClosable variables will be closed.


Whoah! That’s a lot to take in, and to be honest these are not all the improvements to the API that will be available to you in Java 9. However, these are quite important additions that most developers would find useful and be happy to introduce in their code.

The Java 9 release has been cooking for quite some time now, and you should educate yourself in how it could affect you. Now, even more than ever, since the classpath mode will be preserved and your migration path to Java 9 can potentially be quite straightforward. Download the Java 9 binaries, have a play with them, get a feel of the new API and prepare yourself for the bright future it brings!

Read next: