Recently I’ve been doing a presentation entitled, “55 New Features in JDK 9”. In this, I’ve tried to focus almost entirely on things that are not JPMS. What this has revealed is that there are a few areas of change in JDK 9 that could catch people out regarding compatibility with earlier versions. I’ve also been noticing a number of questions related to these things appearing on Stack Overflow

This blog is a summary of all the things I’ve been able to find that might require you to change something when migrating your applications to JDK 9. What I’m not going to do here is talk about JPMS, encapsulation of non-public classes, effects on reflective access, and so on. That’s a whole different set of issues. This collection is just about the other things that you need to be aware of.

Identifiers.&nbsp;JEP 213, Milling Project Coin&nbsp;brings a small change that hopefully won’t affect many people. In earlier versions of Java, it was possible (though not advisory) to use a single underscore as an identifier (i.e. a variable name). In JDK 9, a single underscore is now a keyword. This may sound bizarre, but is the easiest way of preventing its use as an identifier. The plan is that, possibly in JDK 10, it will be possible to use an underscore as an identifier in Lambda expressions only. This will allow a little cleaner syntax for the situation where your Lambda has a single parameter, which is not used in the body of the Lambda (e.g.&nbsp;_ -> foo())

The layout of the JDK has changed (JEP 220): If you rely on the location of JDK specific files relative to $JAVA_HOME, you may need to make some changes. There’s a number of distinct differences here:

There is no more separate jre sub-directory, with a separate copy of the bin, lib, and so on directories. The JDK directory structure is now flat with a single bin directory (and therefore only one copy of the java executable), the lib directory is for native libraries and the jmods directory for the JDK modules. There is also a new conf directory that contains all files that, as administrator, you might need to change to modify the JDK configuration. This has things like networking and logging properties.

The switch to modules means that there are no more rt.jar or tools.jarfiles. If you access these directly, you will need to change your code.

The hprof agent has been removed from JDK 9 (JEP 240) and as a consequence the lib/libhprof.so (or bin/hprof.dll on Windows) files have been deleted as well.

The JDK version string (JEP 223): The old way of defining the version of the JDK was rather confusing. We had JDK 8u131, for example, but if you run java -versionyou’ll get back java version “1.8.0_131”. To simplify this for both humans and applications, the format is now JDK $MAJOR.$MINOR.$SECURITY.$PATCH, so java -version on JDK9 returns java version “9”&nbsp;(this will change once the release is final and we start getting updates). The important thing here is that, if you use the version string of the JVM in your code and rely on the current format you’ll have to make changes to run correctly on JDK 9.

Thread.stop(Throwable)&nbsp;now throws an UnsupportedOperationException, which it did not do before. This method has been deprecated since deprecation first started due to its inherent lack of thread safety. The other version of Thread.stop(), which takes no arguments will still work without throwing an exception (but is still deprecated and you are strongly advised not&nbsp;to use this).

The Java Network Launch Protocol (JNLP) has been updated to allow strict parsing of the configuration files. The format used now conforms to the XML specification by requiring “&” version-range combiner be expressed as “&amp;”. Parsing of the configuration is now strict, meaning some files that would have worked with older versions of Java will now produce errors. More details can be found on the JSR 52 maintenance page.

Related to JPMS the extension mechanism (for optional packages) and the endorsed standards override mechanism have both been removed and replaced with JPMS equivalents. As a consequence, the $JAVA_HOME/lib/ext and $JAVA_HOME/lib/endorsed directories have been deleted. If you recreate these and try putting things in them in the hope that this will still work, it won’t. The JVM will fail to start of it finds these directories, and you will get the following error message:&nbsp;
<JAVA_HOME>/lib/ext exists, extensions mechanism no longer supported; Use -classpath instead.
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

Six previously deprecated public methods have been deleted. This is a pretty big deal, as these are the first APIs to be eliminated in the history of Java. The methods that have been removed are the addPropertyChangeListener()&nbsp;and removePropertyChangeListener()&nbsp;from the java.util.jar.Pack200,&nbsp;java.util.jar.Unpack200 and java.util.logging.LogManager classes.

JRE version selection is no longer available. There were two ways of doing this in the past. The first was from the command line using the -version:<version-id>&nbsp;option. If you use this, the JVM will abort without starting. The second way was from the manifest of a jar file. In this case, JDK 9 will ignore the directive but start up normally. It was felt that forcing people to change the manifest was too onerous compared to changing the command line. Please note that the -versionoption (without a following colon and version-id) still works quite happily to report which version of the Java runtime you have.

Deprecated GC options have been removed (JEP 214). There were a number of specific GC options and combinations of options that were deprecated in JDK 8 (JEP 173). These will not now be recognised and will cause the JVM to abort when it starts. The options to be aware of are shown below
-XX:-UseParNewGC -XX:+UseConcMarkSweepGC
-XX:+UseParNewGC
-Xincgc
-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC
-XX:+CMSIncrementalMode -XX:+UseConcMarkSweepGC -XX:-UseParNewGC
-XX:+UseCMSCompactAtFullCollection
-XX:+CMSFullGCsBeforeCompaction
-XX:+UseCMSCollectionPassingIn JDK 9, the incremental mode of concurrent-mark-sweep (iCMS) has been removed, and the current plan is to remove CMS completely in JDK 10

Command Line Options

This seems to be quite a big change to me, yet I’ve not seen it highlighted (or well documented) so far.

Aside from the GC options noted above, there is a significant change in how logging is handled by the JVM.&nbsp;JEP 158&nbsp;introduces the Unified Logging system, and this is used by GC logging to provide Unified GC logging (JEP 271). This affects a number of commonly used GC logging command line options as well as some other things.

To figure out exactly what had changed I extracted the relevant lines from the OpenJDK source code (specifically, the src/share/vm/runtime/globals.hpp file). By doing a diff, I was able to get a list of all the -XXoptions that had been removed from JDK 8 and all those that had been added to JDK 9. I then wrote a script to use each in turn with a simple app to see what the result of using the options that had been removed from JDK 8 was on JDK 9.

The changes to -XX options can be separated into three groups:

Ignored Command Line Options

If you use one of these, you will get the following warning message, but the JVM will start normally.

Deprecated Command-Line Options

These options will issue a warning when the JVM starts, either telling you which option will be used instead by the JVM or telling you which option you should use. Most of these are related to the move to unified GC logging.

Here are two examples of the warning messages:

warning][gc] -XX:+PrintGC is deprecated. Will use -Xlog:gc instead.

Java HotSpot(TM) 64-Bit Server VM warning: Option CreateMinidumpOnCrash was
deprecated in version 9.0 and will likely be removed in a future release. Use
option CreateCoredumpOnCrash instead.

The table below shows the JDK 8 command line option and the JDK 9 replacement.

JDK 8 OptionJDK 9 Replacement

PrintGC-Xlog:gc

PrintGCDetails-Xlog:gc*

CreateMinidumpOnCrashCreateCoredumpOnCrash (suggestion)

DefaultMaxRAMFractionMaxRAMFraction (suggestion)

TraceBiasedLocking-Xlog:biasedlocking=info

TraceClassLoadingPreorder-Xlog:class+preorder=debug

TraceClassResolution-Xlog:class+resolve=debug

TraceMonitorInflation-Xlog:monitorinflation=debug

TraceRedfineClasses-Xlog:redefine+class*=info

TraceSafepointCleanupTime-Xlog:safepoint+cleanup=info

TraceClassLoading-Xlog:class+load=info

TraceLoaderConstraints-Xlog:class+loader+constraints=info

ConvertSleepToYieldNONE

Options That Won’t Work

These are the most significant options regarding compatibility. If you have used these in the past and don’t change your command line, your application won’t start. When you use one of these you will get the following error message:

Unrecognized VM option ‘<Option>‘
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

Here’s the list of 50 options that won’t work with JDK 9. Check to see if you’ve used any of these in your command line and startup scripts.

AdjustConcurrency

CMSCompactWhenClearAllSoftRefs

CMSDumpAtPromotionFailure

CMSFullGCsBeforeCompaction

CMSIncrementalDutyCycle

CMSIncrementalDutyCycleMin

CMSIncrementalMode

CMSIncrementalOffset

CMSIncrementalPacing

CMSParPromoteBlocksToClaim

CMSPrintEdenSurvivorChunks

CollectGen0First

GCLogFileSize

NumberOfGCLogFiles

ParallelGCVerbose

PrintAdaptiveSizePolicy

PrintCMSInitiationStatistics

PrintCMSStatistics

PrintClassHistogramAfterFullGC

PrintClassHistogramBeforeFullGC

PrintFLSCensus

PrintFLSStatistics

PrintGCApplicationConcurrentTime

PrintGCApplicationStoppedTime

PrintGCCause

PrintGCDateStamps

PrintGCTaskTimeStamps

PrintGCTimeStamps

PrintHeapAtGC

PrintHeapAtGCExtended

PrintJNIGCStalls

PrintOldPLAB

PrintPLAB

PrintParallelOldGCPhaseTimes

PrintPromotionFailure

PrintReferenceGC

PrintTLAB

PrintTenuringDistribution

TraceDynamicGCThreads

TraceGen0Time

TraceGen1Time

TraceMetadataHumongousAllocation

TraceParallelOldGCTasks

UseCMSCollectionPassing

UseCMSCompactAtFullCollection

UseGCLogFileRotation

UseMemSetInBOT

UsePPCLWSYNC

UseVMInterruptibleIO

WorkAroundNPTLTimedWaitHang

Hopefully, this will help you check whether there are any changes you need to make to your application and its configuration as you migrate to JDK 9.