What’s next for JDK 12?

Simon Ritter, Deputy CTO of Azul systems, has written several blog posts that list out all the changes for each of the most recent releases of Java (JDK 10, JDK 11). With JDK 12 just having been released, the following is an excerpt from his post “39 New Features (and APIs) in JDK12” which can be found here.


As you may already know, we are now well into the new six-monthly release cadence. Simon represents Azul on the Java SE JSR Expert Group, and they decided to switch this version to the revised JSR process. This is not radically different, more of a streamlining of the process to fit into the available time more easily.

As you will see, JDK 12 clearly has the least new features of any Java release to date (I counted 109 in JDK 10 and 90 in JDK 11). This is most definitely not a negative; because of the time-driven delivery process, some versions will contain plenty of changes, some will provide less.

I’ll break things down into the obvious logical areas: Java language, libraries, JVM and other JDK features.

Language Changes

What I (and I assume many other people will) consider the most prominent new feature in JDK 12 is switch expressions (JEP 325). This is also the first language change to be included as a preview language feature. The idea of preview language features was introduced at the start of 2018, under JEP 12. Essentially, this is a way of including beta versions of new features. By doing this, it is still possible to make changes based on user feedback and, in an extreme case, remove the feature altogether if it is not well received. The key point about preview features is that they do not get included in the Java SE specification.

Prior to JDK 12, switch was a statement, which to give it a proper definition is a syntactic unit that expresses some action to be carried out. In JDK 12 it has become an expression, which evaluates the contents of the switch to produce a result. One thing to make clear straight away is that it does not impact backward compatibility, so you do not need to change any code you have that uses switch as a statement.

The reason for this change is that there is a widespread pattern in the use of switch. Frequently we use a switch to effectively map from the value being switched on to assigning the value of a variable. I’ll use the example from the JEP since that is both straightforward and easy to understand.

int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
numLetters = 7;
numLetters = 8;
numLetters = 9;
throw new IllegalStateException("Huh? " + day);

As you can see, we’re mapping from the day of the week to the length of the name of that day, which is assigned to numLetters. Now that switch is a statement we can make the assignment once (reducing the potential for erroneous code greatly) using the result of the switch statement:

int numLetters = switch (day) {
case TUESDAY -> 7;
case WEDNESDAY -> 9;
default -> throw new IllegalStateException("Huh? " + day);

Notice two important changes to the syntax we’re all used to.

First, we have finally moved away from each case needing to be separated. The OpenJDK developers have stumbled across a little know syntactic feature called a ‘comma separated list’.

Second, the Lambda expression operator, ->, has been borrowed to simplify how we show what value to return from the switch. You can use break with a value if you really want to. There are a couple of other details about this feature which you can read about in the JEP.

Changes to Java Libraries

There is one change that I think is very useful. There are a number of minor ones as well.

The Streams API has a new Collector, as usual, provided by the Collectors utility class. The new collector can be obtained using the teeing() method. The teeing collector takes three arguments, two Collectors and a BiFunction. To understand what this does I’ve drawn a diagram:

All the values from the input stream are passed into each Collector. The result of each Collector is passed as arguments to the BiFunction to evaluate and generate a final result.

A simple example is one that calculates an average (yes, I know there are already Collectors for this like averagingInt(), but it’s an easy example to help understand the concept).

/* Assume Collectors is statically imported */
double average = Stream.of(1, 4, 2, 7, 4, 6, 5)
summingDouble(i -> i),
(sum, n) -> sum / n));

The first collector calculates the sum of the input stream while the second counts the number of elements. The BiFunction divides the sum by the element count to evaluate the average.


InputStream skipNBytes(long n): This skips over and discards exactly n bytes of data from this input stream. If n is zero or less, then no bytes are skipped.


There is a new package, java.lang.constant, which is part of the JVM Constants API, JEP 334.

Every Java class file has a constant pool, which stores the operands for bytecode instructions in the class. For developers who want to manipulate class files (of which there won’t be that many), this is complicated because of issues around class loading. The JVM Constants API provides symbolic reference types to describe each form of constant (class, loadable constant, MethodHandle, MethodHandle constant and MethodType constant). There is also an enumeration for the kinds of MethodHandle that can be described and three classes for descriptions, one of which is the somewhat oxymoronic, DynamicConstantDesc (which is it, constant or dynamic? Surely it can’t be both).

This has also affected several other classes.

All the following classes now have a describeConstable() method:

  • Class
  • Double
  • Enum
  • Float
  • Integer
  • Long
  • String
  • MethodHandle
  • MethodType
  • VarHandle

Sidenote: As a Brit, I find this quite amusing. The term Constable has been used since the 11thCentury and is how we often refer to policemen. It is also the name of a famous 18thCentury artist, John Constable. It makes me wonder whether a future version will include a method, describeTurner().

Obviously, in this case, it is a contraction of Constant Table not referring to an officer of the law or a landscape artist.

Update: It seems I am wrong in my assumption that Constable is a contraction of Constant Table. A poster on Reddit pointed out that it is something that can be represented in the constant pool, thus const-able. I’m happy to stand corrected, although it would be simpler if the API designers could avoid contractions of constant so that the confusion between whether it is cons-table or const-able is avoided.

The following classes now include a resolveConstantDesc() method

  • Double
  • Enum.EnumDesc
  • Float
  • Integer
  • Long
  • String


Inner classes have been updated to include new Unicode blocks. I always like to see what the Unicode people have found to add so here are some examples:

  • Chess Symbols
  • Mayan numerals — An interesting base 20 numerical system
  • Sogdian — An Eastern Iranian language, which ceased to be used in the 11th Century.
  • Old Sogdian — An older (and, I suspect, of even more limited use) variation of Sogdian


arrayType() returns a Class for an array type whose component type is described by this Class. Using jshell to test this shows:

jshell> (new String[2]).getClass().getName()
$11 ==> "[Ljava.lang.String;"
jshell> (new String[2]).getClass().arrayType()
$12 ==> class [[Ljava.lang.String;
jshell> "foo".getClass().arrayType()
$15 ==> class [Ljava.lang.String;

I’m not totally sure what the point of this method is since all it does is prepend class [ to whatever type the Class represents.

componentType(), which is the same as getComponentType(), which begs the question, why add a redundant method?

descriptorString(). Again, this returns the same result as getName(). However, it is required as Class now implements the TypeDescriptor interface, which is related to the new JVM Constants API.


indent(): adds a number of leading whitespace characters to the String. If the parameter is negative that number of leading whitespace characters will be removed (if possible).

transform(): Applies the provided function to the String. The result does not need to be a String.


VarHandle now has a toString() method to return a compact description.

java.net.SecureCacheResponse and java.net.ssl.HttpsConnection both have a new method, getSSLSession(), which returns an Optional containing the SSLSession in use on the connection.


The Files class has a new method, mismatch(), which finds and returns the position of the first mismatched byte in the content of two files, or -1L if there is no mismatch.


There is a new class, CompactNumberFormat. This is a subclass of NumberFormat that formats a decimal number in a compact form. An example of a compact form would be writing 1,000,000 as 1M, thus requiring two instead of nine characters. NumberFormat and java.text.spi.NumberFormatProvider have been extended to include a new method, getCompactNumberInstance(). There is also a related new enumeration, NumberFormatStyle, which has two values: LONG and SHORT.


CompletionStage now include several overloaded forms of three methods:

  • exceptionallyAsync
  • exceptionallyCompose
  • exceptionallyComposeAsync

These methods extend how a new CompletionStage can be created from an existing CompletionStage if the current one completes exceptionally. Check the API documentation for the details.


The Cipher class has a new toString() method, which returns a string containing the transformation, mode, and provider of the Cipher.


This is a new package in JDK 12 and contains two classes, LdapDnsProvider, which is a service-provider class for DNS lookups when performing LDAP operations. LdapDnsProviderResults encapsulates the result of a DNS lookup for an LDAP URL.


Swing is still being updated! Yes, the filechooser.FileSystemView has a new catchy method, getChooserShortcutPanelFiles(). This returns an array of files representing the values to show by default in the file chooser shortcuts panel.

Learn more about additional changes to JVM

  1. JEP 189: Shenandoah: A Low-Pause-Time Garbage Collector
  2. JEP 344: Abortable Mixed Collections for G1JVM Changes
  3. JEP 346: Promptly Return Unused Committed Memory from G1

and other JDK features:

  1. JEP 230: Microbenchmarking Suite
  2. JEP 340: One Aarch64 Port, Not Two

By visiting the original post with additional perspective from Simon.


JDK 12 provides a small number of new features and APIs, with the switch expression being the most interesting to developers.

With the new release cadence, all users are advised to test their applications on this release. Keeping up with the gradual changes will avoid surprises if you decide to move to a subsequent long-term support release.

We have Zulu Community Edition builds of JDK 12 available completely free of charge to help with your testing.