What is new in Java 13 ?

June 11, 2019

Introduction

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

Last Update: 2020/01/31

Java 13 is released on 2019/09/17.

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

Changes

2020/01/31: Updated the post with GA (13.0.2).
2019/06/11: JEP 350, 351, 353, 354, 355 added. Using EA build 24 (2019/6/6).
2019/03/28: Schedule added.
2019/01/29: First time this post is published.

Java 13 Features

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

JEP 350: Dynamic CDS Archives

This JEP simplifies using application class data sharing (AppCDS). Instead of providing a class list, an archive can be generated when the program exists by using -XX:ArchiveClassesAtExit=<filename>. Then running the application with -XX:SharedArchiveFile=<filename> enables sharing of class data on top of the system default archive in the JDK.

JEP 351: ZGC: Uncommit Unused Memory

ZGC is introduced in JDK 11, but until now it was not returning the unused heap memory to the operating system unlike the G1 Garbage Collector. This JEP addresses this issue and enables this capability by default.

JEP 353: Reimplement the Legacy Socket API

The implementations for java.net.Socket and java.net.ServerSocket is pretty old and this JEP introduces a modern implementation for them. The modern implementation is the default in Java 13, but the old implementations are not removed yet, and they can be used instead by setting the system property jdk.net.usePlainSocketImpl.

No new implementation introduced for java.net.DatagramSocket.

Running a class instantiating Socket and ServerSocket will show this debug output. Here is the default (new):

java -XX:+TraceClassLoading JEP353  | grep Socket
[0.033s][info   ][class,load] java.net.Socket source: jrt:/java.base
[0.035s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.035s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.039s][info   ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800b50840 source: java.net.SocketImpl
[0.042s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.042s][info   ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base
[0.043s][info   ][class,load] sun.nio.ch.SocketDispatcher source: jrt:/java.base
[0.044s][info   ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base
[0.044s][info   ][class,load] java.net.SocksSocketImpl source: jrt:/java.base
[0.044s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.045s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.045s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base

sun.nio.ch.NioSocketImpl above is the new implementation.

Now lets set the system property and run again:

$ java -Djdk.net.usePlainSocketImpl -XX:+TraceClassLoading JEP353  | grep Socket
[0.037s][info   ][class,load] java.net.Socket source: jrt:/java.base
[0.039s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.039s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.043s][info   ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800b50840 source: java.net.SocketImpl
[0.046s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.047s][info   ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base
[0.047s][info   ][class,load] java.net.PlainSocketImpl source: jrt:/java.base
[0.047s][info   ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base
[0.047s][info   ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net
[0.047s][info   ][class,load] java.net.SocketOption source: jrt:/java.base
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net
[0.047s][info   ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net
[0.047s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net
[0.048s][info   ][class,load] jdk.net.LinuxSocketOptions source: jrt:/jdk.net
[0.048s][info   ][class,load] jdk.net.LinuxSocketOptions$$Lambda$2/0x0000000800b51040 source: jdk.net.LinuxSocketOptions
[0.049s][info   ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net
[0.049s][info   ][class,load] java.net.StandardSocketOptions source: jrt:/java.base
[0.049s][info   ][class,load] java.net.StandardSocketOptions$StdSocketOption source: jrt:/java.base
[0.051s][info   ][class,load] sun.net.ext.ExtendedSocketOptions$$Lambda$3/0x0000000800b51440 source: sun.net.ext.ExtendedSocketOptions
[0.057s][info   ][class,load] java.net.DelegatingSocketImpl source: jrt:/java.base
[0.057s][info   ][class,load] java.net.SocksSocketImpl source: jrt:/java.base
[0.058s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.058s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.058s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base

It shows the old implementation java.net.PlainSocketImpl is now used.

JEP 354: Switch Expressions (Preview)

Switch Expressions are introduced in JDK 12 as a preview feature. JEP 354 modifies this feature, it introduces the yield statement for returning a value from a block instead of using break. That means, a switch expression (returning a value) should use yield, and a switch statement (not returning a value) should use break.

For example:

System.out.println(switch (args[0]) {
	case "1" -> 1;
	case "2" -> 2;
	default -> args[0].length();
});

or

System.out.println(switch (args[0]) {
	case "1": yield 1;
	case "2": yield 2;
	default: {
		int len = args[0].length();
		yield len;
	}
});

JEP 355: Text Blocks (Preview)

Raw String Literals feature are introduced in JDK 12 but dropped before the release. This JEP is similar in the sense that it introduces multi-line string literal, a text block.

Similar to Python, a multi-line text block can be defined (instead of using concatenation of single lines) like:

String lines = """
					  	 abc 1
					 	   def 2
					 		 """;

The first character of lines above is a and the last character is 2 but after 2 there is also an end of line marker. So the above definition is same as "abc 1\ndef 2\n". If the line termination at the end is not needed, it should be defined as:

String lines = """
					  	 abc 1
					 	   def 2""";

As it can be clear, the white spaces before abc 1 and def 2 is removed. The exact number of white spaces removed is the minimum number of white spaces of the text block start (the first “”") or the text block end (the last “”").