What’s New in Java 14?

16 major enhancements, 2400 bug fixes, and more

Artem Smotrakov
Feb 9 · 8 min read
Photo by Fab Lentz on Unsplash

Java 14 is going to be released on March 17, 2020. Besides ~2,400 bug fixes and small enhancements, the new version of Java contains 16 major enhancements, also called JEPs (Java Enhancement Proposals).

Let’s take a closer look at the major updates in Java 14: new switch expressions, better NullPointerExceptions, improvements in garbage collection, JFR event streaming, and more.

Image source: Author

Switch Expressions

Let’s assume that we have an enum that describes weekdays. We can write the following code using the new switch expressions:

switch (day) {
case MONDAY -> System.out.println("Aweful");
case TUESDAY, WEDNESDAY -> System.out.println("Okay");
case THURSDAY -> System.out.println("Good");
case FRIDAY -> System.out.println("Great");
case SATURDAY, SUNDAY -> System.out.println("Awesome");

Here we just used a single expression for each case. Note that the switch block doesn't use any break statement, which makes it much shorter. The next example shows how the new switch expressions can return a value:

int numLetters = switch (day) {
case TUESDAY -> 7;
case WEDNESDAY -> 9;

It’s also possible to write multi-line blocks and return a value with a new keyword yield:

int result = switch (s) {
case "Foo" -> 1;
case "Bar" -> 2;
default -> {
System.out.println("Neither Foo nor Bar, hmmm...");
yield 0;

There are several important things that you need to keep in mind when you use the new switch expressions. For example, the cases of new switch expressions have to be exhaustive. It means that, for all possible values, there has to be a matching switch label. Or, since yield is now a keyword, a class with a name yield now becomes illegal in Java 14.

If you'd like to learn more about the new switch expressions, you're welcome to read JEP 361. The authors provided quite a lot of useful info about the new switch expressions.

Helpful NullPointerExceptions

foo.bar = 10;

The NPE is going to look like the following:

Exception in thread "main" java.lang.NullPointerException
at App.main(App.java:17)

The exception message contains a filename and a line where the null dereference happened. For the foo.bar = 10; statement, it's not too difficult to figure out that the NPE was thrown because the foo variable was null. Unfortunately, sometimes it’s not clear what exactly causes an NPE. For example, if either a, b or c is null, then an NPE is going to be thrown:

a.b.c.d = 42;

However, no matter which field was null, the NPE is going to look the same. It doesn’t give any clue which field was actually null.

Here is another example. If one of the nested arrays is null, it results in an NPE:

a[i][j][k] = 99;

Again, no matter which array was null, the NPE is going to look the same.

Java 14 addresses this problem and makes NPEs more friendly. Now the JVM can figure out which variable was null, and then it lets the user know about it in the exception message. For example, a null dereference in the line foo.bar = 10; is going to result in the following NPE:

Exception in thread "main" java.lang.NullPointerException: 
Cannot assign field "bar" because "foo" is null
at App.main(App.java:17)

A null dereference in the line a.b.c.d = 41; is going to result in the following NPE if a.b was null:

Exception in thread "main" java.lang.NullPointerException: 
Cannot read field "c" because "a.b" is null
at App.main(App.java:17)

The new info in NullPointerExceptions may be very helpful in analyzing its root cause and can make the developer’s life a bit easier. By the way, the improvement has been available in SAP’s JVM since 2006. Unfortunately, it took 14 years to finally bring it into OpenJDK.

If you’re interested in the details, the authors of the JEP 358 provided a lot of info about the new feature.

Packaging Tool (Incubator)

JEP 343 introduces the jpackage tool, which packages a Java application into a platform-specific package that includes all of the necessary dependencies. Here’s a list of supported package formats:

  • DEB and RPM on Linux
  • PKG and DMG on macOS
  • MSI and EXE on Windows

Here is an example of how the new tool can be used:

$ jpackage --name myapp --input lib --main-jar main.jar \
--main-class myapp.Main

It takes the lib/main.jar file and produces a package in the format most appropriate for the system on which it is run. The entry point is the myapp.Main class.

The JEP’s authors provided quite a lot of useful information about the new tool.

Although the jpackage tool is available in JDK 14, it's delivered as an incubator module, which means that the functionality is not guaranteed to be stable and may be revised in a future release.

Better Garbage Collection

JEP 345 improves the G1 garbage collector by implementing NUMA-aware memory allocation. By the way, NUMA stands for Non-Uniform Memory Access. This feature has been implemented in the parallel garbage collector for a long time. Now it can be enabled in the G1 as well by running Java with a new +XX:+UseNUMA command-line option. This should improve G1 performance on large machines.

JEP 363 removes the Concurrent Mark Sweep (CMS) garbage collector which was deprecated a couple of years ago. Goodbye CMS!

JEP 364 and JEP 365 make the Z garbage collector (ZGC) available on macOS and Windows. ZGC is a concurrent garbage collector that was added to the JVM a couple of years ago. ZGC tries to reduce pause times for garbage collections and can handle heaps of size ranging from a few hundred megabytes to multi-terabytes. Previously, the collector could run only on Linux.

JEP 366 deprecates the combination of the Parallel Scavenge and Serial Old garbage collection algorithms. This combination had to be enabled by the user with the -XX:+UseParallelGC -XX:-UseParallelOldGC command-line options. The authors believe that the combination is uncommon but requires a significant amount of maintenance effort. In fact, the option -XX:UseParallelOldGC is now deprecated. A warring is going to be displayed if the deprecated modes are used.

JFR Event Streaming

To consume the data provided by JFR, a user has to start a recording, stop it, dump the contents to disk, and then parse the recording file. This works quite well for application profiling but not for monitoring purposes.

In Java 14, the JFR allows users to subscribe to events asynchronously. Users can now register a handler that’s going to be invoked in response to the arrival of an event. The RecordingStream class provides a uniform way to filter and consume events. Here is an example provided by the JEP's authors:

More info can be found in JEP 349.

Language preview features

First, JEP 305 extends the instanceof operator with a binding variable. Here is an example:

if (obj instanceof String s) {
// can use s here

If obj is an instance of String, then it is cast to String and assigned to the binding variable s.

Second, JEP 359 introduces records to the Java language. A record has a name and a state description. The state description declares the components of the record. A record may also have a body. Here is a short example:

record Point(int x, int y) {}

Third, after collecting feedback for Java 13, JEP 368 adds a couple of new escape sequences for the text blocks that were previously introduced in Java 13 as a language preview feature.

Unfortunately, these three updates are still only available as preview language features that are not enabled by default. To enable the new syntax, you’ll have to run the Java compiler with --enable-preview --release 14 options and then launch java with --enable-preview option:

$ javac -d classes --enable-preview --release 14 Test.java
$ java -classpath classes --enable-preview Test

The Rest

JEP 370 introduces an API to allow Java applications to safely and efficiently access foreign memory outside of the Java heap. Sounds scary. The new API should become an alternative to the java.nio.ByteBuffer and sun.misc.Unsafe classes. This feature is provided as an incubating module.

JEP 352 adds new file mapping modes so that the FileChannel API can be used to create MappedByteBuffer instances that refer to non-volatile memory (NVM).

The Pack200 tool was deprecated in Java 11. Now JEP 367 removed the tool and its API.

In case you know about Solaris and SPARC, JEP 362 drops support for the Solaris/SPARC, Solaris/x64, and Linux/SPARC platforms. In the future, the ports on these platforms most likely are going to be removed from OpenJDK.


Better Programming

Advice for programmers.

Thanks to Zack Shapiro

Artem Smotrakov

Written by

I write about Java and security

Better Programming

Advice for programmers.

More From Medium

More from Better Programming

More from Better Programming

More from Better Programming

More from Better Programming

The Zero-Dollar Infrastructure Stack


Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade