What is new in Java 14 ?

February 01, 2020


Java 14 is released on 2020/03/17.

This is an alive post of what will become Java 14, and, as expected, this post will expand and change over time, until the development of Java 14 is frozen in late 2019. I am planning to update this post when a new feature (JEP) is targeted for JDK 14, or when there is an important update on an already targeted JEP.

If something is a preview feature, it is fully specified and implemented, but provided in a release to gather feedback, so it is not a permanent change yet. You need to use --enable-preview to use such features.


2020/02/03: Typo fixes.
2020/01/31: Java 14 is in Rampdown Phase Two. Java 14 EA Build 34 (2020/1/29).

Java 14 Features

The list is taken from the OpenJDK JDK 14 project page.

JEP 305: Pattern Matching for instanceof (Preview)

instanceof can be used with an identifier which functions as a local variable if instanceof expression is true, so there is no need for a separate declaration and a cast.

final Object o = switch (args[0]) {

	case "s" -> "test";
	default -> new Object();


if (o instanceof String s) {
	// s is effectively s = (String) o;
} else {
	System.out.println("not a string");

JEP 343: Packaging Tool (Incubator)

This incubating feature provides a new tool jpackage to create platform-specific packages from Java applications. That means deb or rpm files in Linux, pkg or dmg files in macOS and msi or exe files in Windows.

I created a simple HelloWorld app, and created a jar containing this class and put the jar in a folder named app. To create the package:

$ jpackage --name helloworld --input app --main-jar helloworld.jar --main-class JEP343

Then installing the created file helloworld_1.0-1_amd64.deb on Ubuntu:

$ sudo apt install ./helloworld_1.0-1_amd64.deb
Reading package lists... Done
Building dependency tree
Reading state information... Done
Note, selecting 'helloworld' instead of './helloworld_1.0-1_amd64.deb'
The following NEW packages will be installed:
0 upgraded, 1 newly installed, 0 to remove and 48 not upgraded.
Need to get 0 B/31.3 MB of archives.
After this operation, 138 MB of additional disk space will be used.
Get:1 /home/mete/14ex/helloworld_1.0-1_amd64.deb helloworld amd64 1.0-1 [31.3 MB]
Selecting previously unselected package helloworld.
(Reading database ... 74917 files and directories currently installed.)
Preparing to unpack .../helloworld_1.0-1_amd64.deb ...
Unpacking helloworld (1.0-1) ...
Setting up helloworld (1.0-1) ...

Package is installed under /opt (confirmed by dpkg-deb -c helloworld_1.0-1_amd64.deb):

$ cd /opt/
$ ls
$ cd helloworld/
$ ls
bin  lib  share
$ cd bin/
$ ls
$ ./helloworld
Hello World!

JEP 345: NUMA-Aware Memory Allocation for G1

G1 garbage collector is now NUMA-aware to support large systems.

JEP 349: JFR Event Streaming

JDK Flight Recorder is improved to support continuous monitoring of JDK Flight Recorder data. So rather than recording and then parsing the recorded events file, the events can now be streamed either in real-time without using a file, or they can be streamed from a file.

JEP 352: Non-Volatile Mapped Byte Buffers

FileChannel API is improved to support creating mapped byte buffers on non-volatile memory (persistent memory). This feature is only supported in Linux/x64 and Linux/AArch64 platforms.

JEP 358: Helpful NullPointerExceptions

Improves the usability of NullPointerExceptions by providing more information on which field and/or operation NullPointerException has occurred.

There are various different messages, a simple example is:

final String[] s = new String[2];

This code normally produces this error:

Exception in thread "main" java.lang.NullPointerException
	at JEP358.main(JEP358.java:7)

which points the line where the error occurred, but it is not clear if s is null or an element of s is null.

If you execute this code with -XX:+ShowCodeDetailsInExceptionMessages flag, error message changes to this:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because "<local1>[1]" is null
	at JEP358.main(JEP358.java:7)

which indicates the element [1] is null.

JEP 359: Records (Preview)

Introduces record declaration, which is a type of restricted class, it is final, not abstract, and all of its fields are final as well.

For example:

record Point(int x, int y) {};

final Point p1 = new Point(1, 2);
final Point p2 = new Point(1, 2);

if (p1.equals(p2)) {


Point[x=1, y=2]

as you see, equals and toString methods are automatically provided (in addition to hashCode, constructor and read accessor methods).

JEP 361: Switch Expressions (Standard)

Switch Expressions, which was a preview feature in Java 13, becomes a standard language feature. You can check What is new in Java 12 and What is new in Java 13 posts for some examples.

JEP 362: Deprecate the Solaris and SPARC Ports

Solaris/SPARC, Solaris/x64, and Linux/SPARC ports are deprecated and will be removed in a future release.

JEP 363: Remove the Concurrent Mark Sweep (CMS) Garbage Collector

CMS Garbage Collected was deprecated in Java 9, and it is removed with Java 14.

JEP 364: ZGC on macOS

ZGC was introduced in Java 11, but it was only supported in Linux. Now it is also available in macOS.

JEP 365: ZGC on Windows

ZGC was introduced in Java 11, but it was only supported in Linux. Now it is also available in Windows (after version 1803).

JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination

The Parallel Scavenge young and Serial old garbage collector combination is deprecated due to little use and large maintenance effort.

JEP 367: Remove the Pack200 Tools and API

Pack200 tools and api was deprecated in Java 11, and it is removed with Java 14.

JEP 368: Text Blocks (Second Preview)

This was already a preview feature in Java 13, and it continues to be a preview feature in Java 14 as to be, with two new escape sequences.

\<end-of-line> suppresses the line termination, and \s is translated into a single space. So the following code:

final String s = """
	no line term after this\
	and a single space between quote: "\s"


produces this output:

no line term after this and a single space between quotes: " "

JEP 370: Foreign-Memory Access API (Incubator)

This incubating feature enables efficient access to native memory segments out of JVM heap space (off-heap). You need to add module jdk.incubator.foreign manually to try this feature.

The simple example below allocates a 1K memory out of JVM heap space and prints its base address.

try (MemorySegment segment = MemorySegment.allocateNative(1024)) {

	MemoryAddress base = segment.baseAddress();



which prints:

WARNING: Using incubator modules: jdk.incubator.foreign
MemoryAddress{ region: MemorySegment{ id=0x45f84202 limit: 1024 } offset=0x0 }

In order to use this memory segment, memory access VarHandle should be used. For example:

final VarHandle h = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());

try (MemorySegment segment = MemorySegment.allocateNative(1024)) {

	MemoryAddress base = segment.baseAddress();

	h.set(base, 1024);



This stores 1024 as int at the base of the off-heap memory segment.