It feels like it was only a few weeks since JDK 9 was launched, and that’s because it was. Things move on, however, and with the new release cadence for OpenJDK, JDK 10 has already reached the release candidate milestone.

I’ve seen a variety of blog posts on the subject of what’s new in JDK 10, but they tend to stick just to the big items defined through the JDK Enhancement Proposals (JEPS). For this blog, I thought I’d see if I can list out absolutely everything that has changed (both added and removed) in JDK 10.

Having been giving presentations on Java SE for some time, I joked during my recent “55 New Features in JDK 9” presentation that the next one would be “5 New Features in JDK 10”. It turns out there’s more than you might think in JDK 10, even with only six-months of development time.

Even though I no longer work for Oracle, I will put a safe harbour statement here, so there’s no misunderstanding. This list is compiled from the publicly available information: JDK Enhancement Proposals (JEPs), the OpenJDK bug database and the Java SE 10 public review specification (JSR 383). Whilst being diligent in my research, there may be things that change before JDK 10 is finally released.

Big Things

There are twelve JEPs included in JDK 10

[286] Local-variable type inference: This is the only real feature for developers in JDK 10. It introduces var to Java, something that is common in other languages, such as JavaScript. As long as the compiler can infer the type, you no longer need to state explicitly the type of a local-variable. A simple example is: var x = new ArrayList<String>(); This eliminates the duplication of the ArrayList<String> type definition that we would have had to use before. I encourage you to read the JEP, as there are some rules about where this syntax can and can’t be used. One interesting thing to note about this is that var does not become a keyword but is, instead, a reserved type. This means you can still use var as a variable, method or package name but now (although I’m sure you never would) you can no longer have a class called

[310] Application Class-data Sharing: CDS was introduced in JDK 5 to improve the performance of the JVM startup and reduce the resource footprint when multiple JVMs are running on the same physical or virtual machine. JDK 10 will extend CDS to allow the built-in system class loader, the built-in platform class loader, and custom class loaders to load archived classes. Previously, use of CDS had been restricted to the bootstrap class loader only.

[314] Additional Unicode Language-Tag Extensions: This will enhance the java.util.Locale class and related APIs to implement additional Unicode extensions of BCP 47 language tags. Specifically, tags for currency type, the first day of the week, region override and time zone will now be supported.

[322] Time-Based Release Versioning: As I discussed in an earlier blog post, we have had almost as many JDK version string formats as we’ve had versions of the JDK. Hopefully, this one will be the last we’ll need, and we can stick with this. The format being used is very similar to that introduced in JDK 9 to give a more semantic form. The one thing that bugs me about this is the inclusion of an INTERIM element, which as the JEP states, “is always zero”. Well, if it’s always zero, what’s the point of having it? Yes, they say it’s reserved for future use, but I still don’t like it. This is unnecessary complexity in my opinion. This also eliminates the rather odd situation we had with JDK 9. The first update was JDK 9.0.1, which is quite logical. The second update was JDK 9.0.4, which isn’t logical. The reasoning is that, under the JDK 9 version-numbering scheme, space is left between updates in case an emergency, unscheduled update is required. Since no update had been necessary why not simply call it JDK 9.0.2?

[319] Root Certificates: This will provide a default set of root Certification Authority (CA) certificates in the JDK. Critical security components such as TLS will now work by default in OpenJDK builds. This is a beneficial addition and is probably part of the work Oracle is undertaking to ensure that OpenJDK binaries and Oracle JDK binaries are functionally the same.

[307] Parallel Full GC for G1: G1 is designed as a low-latency garbage collector (but will still resort to a full compacting collection if it cannot keep up with the rate of promotion to the old generation or fragmentation of the heap). Prior to JDK 9, the default collector was the parallel, throughput, collector. To reduce differences in the performance profile of applications using the default collector, G1 now has a parallel full collection. An improvement but, if you still want proper, reliable low-latency GC, then you need to look at Zing.

[313] Remove the Native-Header Generation Tool: Java 9 started some serious housekeeping of the JDK, and this is a continuation of that. It is no longer necessary to have a separate tool to generate header files when compiling JNI code, as this can be done through javac. At some point, JNI will be replaced by the results of Project Panama, but it’s not clear when that will happen yet.

[304] Garbage Collector Interface: This is not an interface that can be used by developers to control garbage collection; instead it is a clean interface within the JVM source code to allow alternative collectors to be quickly and easily integrated. If nothing else this is good news for Azul, as it will reduce the amount of work we need to do when migrating Zing to a new version of the JDK.

[312] Thread-local handshakes: This is quite a low-level change inside the JVM that will now allow execution of a callback on threads without performing a global VM safe point. This will make it both possible and cheap to stop individual threads and not just all threads or none.

[316] Heap Allocation on Alternative Memory Devices: Hardware technologies are continually evolving, and it is now possible to use non-volatile RAM that has the same interface and similar performance characteristics to conventional DRAM. This JEP will enable the JVM to use a heap that is configured to use different types of memory system.

[317] Experimental Java-Based JIT Compiler: Project Metropolis was announced recently, which proposes rewriting a large part of the JVM in Java. When you first think about this, it seems rather odd. If the JVM is written in Java, don’t you need a JVM to run the JVM? Recursively this leads to a nice hall-of-mirrors analogy. The reality is that just because you write the JVM in Java doesn’t imply that you have to compile it to bytecodes, you can use AOT compilation and then JIT compile the code as it’s running to improve performance. This JEP introduces the Graal compiler research project to the JDK. This is some of the groundwork that will help make Metropolis a reality and enable the JVM performance to match (hopefully exceed) that of the current version written in C++.

[296]: Consolidate the JDK Forest into a Single Repository: In JDK 9 there are eight repos: root, corba, hotspot, jaxp, jaxws, jdk, langtools, and nashorn. In JDK 10 these will be merged into a single repository to make it possible to perform an atomic commit across repositories of inter-dependent changesets.

New APIs

There are 73 additions to the standard class libraries.

java.awt.Toolkit

int getMenuShortcutKeyMaskEx() : Determines which extended modifier key is the appropriate accelerator key for menu shortcuts.

: Determines which extended modifier key is the appropriate accelerator key for menu shortcuts. java.awt.geom.Path2D :

void trimToSize() : Trims the capacity of this Path2D instance to its current size. An application can use this operation to minimise the storage of a path. This has also been added to the inner Path2D.Double and Path2D.Float classes.

: : Trims the capacity of this Path2D instance to its current size. An application can use this operation to minimise the storage of a path. This has also been added to the inner Path2D.Double and Path2D.Float classes. java.io.ByteArrayOutputStream:

String toString(Charset) : Overloaded toString that converts the buffer’s contents into a string by decoding the bytes using the specified charset.

: Overloaded toString that converts the buffer’s contents into a string by decoding the bytes using the specified charset. java .io.PrintStream:

lang.io.PrintWriter:

Both these classes have three new constructors that take an additional charset argument.

Both these classes have three new constructors that take an additional charset argument. java.io.Reader:

long transferTo(Writer): reads all characters from this reader and writes the characters to the given writer in the order that they are read.

reads all characters from this reader and writes the characters to the given writer in the order that they are read. java.lang.Runtime.Version:

There are four new methods that return an integer value of the new (JEP 322) version string fields: feature(), interim(), patch() and update().

There are four new methods that return an integer value of the new (JEP 322) version string fields: feature(), interim(), patch() and update(). java.lang.StackWalker.StackFrame :

String getDescriptor() : Returns the descriptor of the method represented by this stack frame as defined by The Java Virtual Machine Specification.

String getMethodType() :Returns the MethodType representing the parameter types and the return type for the method represented by the stack frame.

: : Returns the descriptor of the method represented by this stack frame as defined by The Java Virtual Machine Specification. :Returns the MethodType representing the parameter types and the return type for the method represented by the stack frame. java.lang.invoke.MethodType:

Class<?> lastParameterType(): Returns the last parameter type of this method type. If this type has no parameters, the sentinel value void.class is returned instead.

Returns the last parameter type of this method type. If this type has no parameters, the sentinel value void.class is returned instead. java.lang.management.RuntimeMXBean:

long getPid(): Returns the pid of the running Java virtual machine.

Returns the pid of the running Java virtual machine. java.lang.management.ThreadMXBean:

ThreadInfo[] dumpAllThreads(boolean, boolean, int): Returns the thread information for all live threads with a stack trace of the specified maximum number of elements and synchronization information.

ThreadInfo[] getThreadInfo(long[], boolean, boolean, int): Returns the thread information for each thread whose identity is in the input array, with a stack trace of the specified maximum number of elements and synchronization information.

Returns the thread information for all live threads with a stack trace of the specified maximum number of elements and synchronization information. Returns the thread information for each thread whose identity is in the input array, with a stack trace of the specified maximum number of elements and synchronization information. java.lang.reflect.MalformedParameterizedTypeException: A new constructor has been added that takes a detail message in the form of a String as a parameter.

A new constructor has been added that takes a detail message in the form of a String as a parameter. java.net.URLDecoder:

java.net.URLEncoder:

both these classes have new overloaded decode and encode methods that take a charset as an additional parameter.

both these classes have new overloaded decode and encode methods that take a charset as an additional parameter. java.nio.channels.Channels:

Two new static overloaded methods, newReader(ReadByteChannel, Charset) and newWriter(WriteByteChannel, Charset) that allow the use of a charset.

Two new static overloaded methods, newReader(ReadByteChannel, Charset) and newWriter(WriteByteChannel, Charset) that allow the use of a charset. java.nio.file.FileStore:

long getBlockSize(): Returns the number of bytes per block in this file store.

Returns the number of bytes per block in this file store. java.time.chrono: Three classes in this package, HijrahEra, MiinguoEra and ThaiBuddhistEra, have had the same method added

String getDisplayName(TextStyle, Locale): This returns the textual name used to identify the era, suitable for presentation to the user.

Three classes in this package, HijrahEra, MiinguoEra and ThaiBuddhistEra, have had the same method added This returns the textual name used to identify the era, suitable for presentation to the user. java.time.format.DateTimeFormatter:

localizedBy(Locale): Returns a copy of this formatter with localized values of the locale, calendar, region, decimal style and/or time zone, that supersede values in this formatter.

Returns a copy of this formatter with localized values of the locale, calendar, region, decimal style and/or time zone, that supersede values in this formatter. java.util : DoubleSummaryStatistics, IntSummaryStatistics and LongSummaryStatistics all have a new constructor that takes four numeric values. It constructs a non-empty instance with the specified count, minimum, maximum, and sum.

: DoubleSummaryStatistics, IntSummaryStatistics and LongSummaryStatistics all have a new constructor that takes four numeric values. It constructs a non-empty instance with the specified count, minimum, maximum, and sum. java.util.List:

java.util.Map:

java.util.Set: Each of these interfaces gains a new static method, copyOf(Collection). These return an unmodifiable List, Map or Set containing the elements of the given Collection, in its iteration order.

Each of these interfaces gains a new static method, copyOf(Collection). These return an unmodifiable List, Map or Set containing the elements of the given Collection, in its iteration order. java.util.Optional:

java.util.OptionalDouble:

java.util.OptionalInt:

java.util.OptionalLong: Each of these classes gets a new method, orElseThrow(), which essentially does the same as get(), i.e. if the Optional holds a value it is returned. Otherwise, a NoSuchElementException is thrown.

Each of these classes gets a new method, orElseThrow(), which essentially does the same as get(), i.e. if the Optional holds a value it is returned. Otherwise, a NoSuchElementException is thrown. java . util.Formatter:

java.util.Scanner:

Both these classes have three new constructors, all of which take a charset in addition to other arguments.

. Both these classes have three new constructors, all of which take a charset in addition to other arguments. java.util.Properties : This has a new constructor that takes an int argument. This creates an empty property list with no default values, and with an initial size accommodating the specified number of elements without the need to dynamically resize. There is also a new, overloaded, version of the replace method that takes three Object parameters and returns a boolean. This replaces the entry for the specified key only if currently mapped to the specified value.

: This has a new constructor that takes an int argument. This creates an empty property list with no default values, and with an initial size accommodating the specified number of elements without the need to dynamically resize. There is also a new, overloaded, version of the replace method that takes three Object parameters and returns a boolean. This replaces the entry for the specified key only if currently mapped to the specified value. java . SplittableRandom :

void nextBytes(byte[]): Fills a user-supplied byte array with generated pseudorandom bytes.

. : Fills a user-supplied byte array with generated pseudorandom bytes. java.util.concurrent.FutureTask : A toString() method has been added, that returns a string identifying the FutureTask, as well as its completion state. The state, in brackets, contains one of the strings “Completed Normally” , “Completed Exceptionally” , “Cancelled”, or “Not completed”.

: A toString() method has been added, that returns a string identifying the FutureTask, as well as its completion state. The state, in brackets, contains one of the strings “Completed Normally” , “Completed Exceptionally” , “Cancelled”, or “Not completed”. java.util.concurrent.locks.StampedLock :

boolean isLockStamp(long) : Returns whether a stamp represents holding a lock.

boolean isOptimisticReadStamp(long) : Returns whether a stamp represents a successful, optimistic read.

boolean isReadLockStamp(long): Returns whether a stamp represents holding a lock non-exclusively (i.e. a read lock).

boolean isWriteLockStamp(long) : Returns whether a stamp represents holding a lock exclusively (i.e. a write lock).

: : Returns whether a stamp represents holding a lock. : Returns whether a stamp represents a successful, optimistic read. Returns whether a stamp represents holding a lock non-exclusively (i.e. a read lock). : Returns whether a stamp represents holding a lock exclusively (i.e. a write lock). java . jar.JarEntry:

String getRealName() : Returns the real name of this JarEntry. If this JarEntry is an entry of a multi-release jar file, which is configured to be processed as such, the name returned by this method is the pathname of the versioned entry that the JarEntry represents, rather than the path name of the base entry that ZipEntry.getName() returns. If the JarEntry does not represent a versioned entry of a multi-release jar file or the jar file is not configured for processing as a multi-release jar file, this method returns the same name that ZipEntry.getName() returns.

. : Returns the real name of this JarEntry. If this JarEntry is an entry of a multi-release jar file, which is configured to be processed as such, the name returned by this method is the pathname of the versioned entry that the JarEntry represents, rather than the path name of the base entry that ZipEntry.getName() returns. If the JarEntry does not represent a versioned entry of a multi-release jar file or the jar file is not configured for processing as a multi-release jar file, this method returns the same name that ZipEntry.getName() returns. java.util.jar.JarFile:

Stream<JarEntry> versionedStream() : Returns a Stream of the versioned jar file entries. Like the getRealName method of JarEntry, this is related to multi-release jar files.

: Returns a Stream of the versioned jar file entries. Like the getRealName method of JarEntry, this is related to multi-release jar files. java.util.spi.LocaleNameProvider:

getDisplayUnicodeExtensionKey(String, Locale): Returns a localised name for the given Unicode extension key.

getDisplayUnicodeExtensionType(String, String, Locale): Returns a localised name for the given Unicode extension key.

Returns a localised name for the given Unicode extension key. Returns a localised name for the given Unicode extension key. java.util.stream.Collectors:

toUnmodifiableList():

toUnmodifiableSet():

toUnmodifiableMap(Function, Function):

toUnmodifiableMap(Function, Function, BinaryOperator): These four new methods return Collectors that accumulate the input elements into the appropriate unmodifiable collection.

These four new methods return Collectors that accumulate the input elements into the appropriate unmodifiable collection. java.lang.model.SourceVersion : This now has a field, RELEASE_10 that represents the version for JDK 10.

: This now has a field, RELEASE_10 that represents the version for JDK 10. java.lang.model.util.TypeKindVisitor6 :

javax.lang.model.util.TypeKindVisitor9:

I have to confess I’ve never even heard of these classes

R visitNoTypeAsModule(NoType, P) : Visits a MODULE pseudo-type. I’m not sure why only these two classes got this method as there are also Visitor7 and Visitor8 variants.

: I have to confess I’ve never even heard of these classes : Visits a MODULE pseudo-type. I’m not sure why only these two classes got this method as there are also Visitor7 and Visitor8 variants. javax.remote.management.rmi.RMIConnectorServer :

This class has had two fields added: CREDENTIALS_FILTER_PATTERN and SERIAL_FILTER_PATTERN.

: This class has had two fields added: CREDENTIALS_FILTER_PATTERN and SERIAL_FILTER_PATTERN. javax . ButtonModel : Look, Swing is still being updated!

ButtonGroup getGroup(): Returns the group that the button belongs to. Normally used with radio buttons, which are mutually exclusive within their group.

. : Look, Swing is still being updated! Returns the group that the button belongs to. Normally used with radio buttons, which are mutually exclusive within their group. javax.plaf.basic.BasicMenuUI:

Dimension getMinimumSize(JComponent): Returns the specified component’s minimum size appropriate for the look and feel.

Changes to the Java Virtual Machine Specification

These are fairly small:

Section 4.6: Class file format (Page 99). A small change in respect of method access flags.

Section 4.7: Module attribute (Page 169). JDK 10 no longer allows ACC_TRANSITIVE or ACC_STATIC_PHASE to be set if the module is not java.base.

Section 4.10: Verification of class files (page 252). The dup2 instruction has changed the definition of typesafe form 1, reversing the order of the types in the canSafleyPushList section (you need to look really carefully to spot this).

Section 5.2: Java Virtual Machine Startup (page 350). The description adds that a user-defined classloader (other than the bootstrap classloader) may be used when creating an initial class or interface.

Changes to the Java Language Specification

There are a few more here, but mostly to support local-variable type inference.

Section 3.8: Identifiers (Page 23). Equality of identifiers is now considered after ignorable characters have been ignored. This seems logical.

(Page 24) A new token, TypeIdentifier, is declared that supports the new use of local-variable type inference and the use of var is not a keyword, but rather an identifier with special meaning as the type of a local variable declaration.

(Page 24) A new token, TypeIdentifier, is declared that supports the new use of local-variable type inference and the use of var is not a keyword, but rather an identifier with special meaning as the type of a local variable declaration. Section 4.10.5: Type Projections (Page 76). This is a rather complicated section that relates to capture variables, nested classes and how this all works with local-variable type inference. Rather than try to explain it I suggest you read this section in the spec.

Section 6.1: Declarations (Page 134). A small change to reflect the use of the TypeIdentifier to support local-variable type inference.

Section 6.5: Determining the Meaning of a Name (Page 153, 158 and 159). A change to the TypeName based on the use of TypeIdentifier.

Section 6.5.4.1: Simple PackageOrTypeNames (Page 160)

Section 6.5.4.2: Qualified PackageOrTypeNames (Page 160). Both of these have minor changes related to the use of TypeIdentifier.

Section 7.5.3: Single-Static-Import Declarations (Page 191). This changes the rules about importing static types that have the same name. This now becomes an error unless the types are the same, in which case the duplication is ignored.

Section 7.7.1: Dependences (Page 198). If you state explicitly that a module requires java.base, then you can no longer have a modifier (such as static) after the requires keyword.

Section 8.4.1: Formal Parameters (Page 244). A receiver parameter may appear only in the FormalParameterList of either an instance method or a constructor of an inner class where the inner class is not declared in a static context.

Section 9.7.4: Where Annotations May Appear (Page 335). There is a change related to local-variable type inference.

Section 14.4: Local Variable Declaration Statements (Page 433). A significant number of changes required to implement local-variable type inference.

Section 14.14.2: The Enhanced for Statement (Page 455). This construct has been updated to include support for local-variable type inference.

Section 14.20.3: try-with-resources (Page 474). This construct has been updated to include support for local-variable type inference.

Finally, Chapter 19, Syntax, has been updated in various places to reflect the use of TypeIdentifier rather than just Identifier, again to support local-variable type inference.

Miscellaneous Things

If the Kerberos configuration file krb5.conf includes an INCLUDEDIR directive files ending in .conf in that directory will now be included by default.

The Java launcher options, -d32 and –d64, were deprecated previously and have now been removed. If you use these, you need to change your startup scripts, as they will prevent the JVM from starting.

The old (JDK 6, JDK 7 and JDK 8) Doclet has been removed. This was superseded by a new version in JDK 9, which is the only one available in JDK 10.

The newFactory() method was incorrectly deprecated in JDK 9. The method has been de-deprecated (or should that be precated?) in JDK 10.

A new inline Javadoc tag, {@summary…} has been introduced. This eliminates the need for automatic generation of an API summary that didn’t always generate what was required.

The BiasedLockingStartupDelay was 4000 (4 seconds) and is now zero (so no startup delay).

The following classes in the com.sun.security.auth package were previously deprecated and have now been removed: PolicyFile SolarisNumericGroupPrincipal SolarisNumericUserPrincipal X500Principal SolarisLoginModule SolarisSystem

The following field and methods in the java.lang.SecurityManager class were deprecated (since before JDK 1.2!) and have now, finally, been removed: inCheck (field) getInCheck classDepth classLoaderDepth currentClassLoader currentLoadedClass inClass inClassLoader

The following obsolete internationalization methods have been removed from the java.lang.Runtime class: getLocalizedInputStream getLocalizedOutputStream

Several obsolete Hotspot –X options have been removed: -Xoss, -Xsqnopause, -Xoptimize, -Xboundthreads and –Xusealtsigs.

The policytool has been removed from the JDK.

The javadoc tool can now support multiple stylesheets via the –add-stylesheets command line flag.

The JVM has been modified to be aware that it is running in a Docker container. The number of CPUs and allocated memory for the container will be used when configuring thread pools and GC rather than values reported directly from the OS. There are three new command line flags to give greater control: -XX:InitialRAMPercentage, -XX:MaxRAMPercentage and -XX:MinRAMPercentage

There is a new system property, jdk.disableLastUsageTracking, that will, not surprisingly, disable JRE last usage tracking.

As you can see, despite there only being six months since JDK 9, there are actually quite a large number of changes. Sure, some of them are pretty small, but I think this shows that right away the new six-month release cadence will work in terms of delivering improvements to the Java platform more quickly.

Zulu builds of JDK 10 will be available shortly.

Let’s see what JDK 11 brings.