What's new in Java 13

Keywords: Java

Java 13 Officially released on September 17, 2019, please Download Java 13 here.

Some new features in Java 13

1. JEP 350 dynamic CDS file

The JEP enhances the functionality introduced in Java 10 by simplifying the process of creating CDS files JEP 310 application class data sharing.

If the program exists, a CDS Archive - XX:ArchiveClassesAtExit will be created

$ java -XX:ArchiveClassesAtExit=hello.jsa -cp hello.jar Hello

Use the CDS file above to run the program.

$ bin/java -XX:SharedArchiveFile=hello.jsa -cp hello.jar Hello

The idea behind class data sharing (CDS) is to improve startup performance by creating a class data archive once and then using it, so the JVM does not need to create it again.

Please read the following articles to learn more about CDS:

2. JEP 351 ZGC: uncommit unused memory

Should JEP bit 333: Z garbage collector When Java 11 is launched, clean up the heap memory when providing a short pause time. However, even if the memory is not used for a long time, it will not return unused heap memory to the operating system.

The JEP enhances ZGC by returning unused heap memory to the operating system.

3. JEP-353 re implements the old socket API

The underlying implementation of java.net.Socket and java.net.ServerSocket is very old, which can be traced back to JDK 1.0. It is a mixture of traditional Java and C code, which is difficult to maintain and debug. The JEP introduces a new basic implementation for the Socket API, which is the default implementation in Java 13.

Before Java 13, it used PlainSocketImpl as SocketImpl

ServerSocket.java

public class ServerSocket implements java.io.Closeable {
    /**
     * The implementation of this Socket.
     */
    private SocketImpl impl;
}

In Java 13, it introduces a new NioSocketImpl class to replace PlainSocketImpl. However, if there is a problem, we can still switch back to the old implementation by setting the jdk.net.usePlainSocketImpl system property

Check out a simple Socket example.

JEP353.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

public class JEP353 {
    public static void main(String[] args) {
        try (ServerSocket serverSocket = new ServerSocket(8888)){

            boolean running = true;
            while(running){

                Socket clientSocket = serverSocket.accept();
                //do something with clientSocket
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Track the class loading of the above Socket class. In Java 13, the default implementation is NioSocketImpl

Terminal station

D:\test>javac JEP353.java

D:\test>java JEP353

D:\test>java -XX:+TraceClassLoading JEP353  | findStr Socket

[0.040s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.040s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.040s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
[0.040s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.040s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.044s][info   ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800ba0840 source: java.net.SocketImpl
[0.047s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base

[0.047s][info   ][class,load] sun.nio.ch.NioSocketImpl source: jrt:/java.base

[0.047s][info   ][class,load] sun.nio.ch.SocketDispatcher source: jrt:/java.base
[0.052s][info   ][class,load] java.net.SocketAddress source: jrt:/java.base
[0.052s][info   ][class,load] java.net.InetSocketAddress source: jrt:/java.base
[0.052s][info   ][class,load] java.net.InetSocketAddress$InetSocketAddressHolder source: jrt:/java.base
[0.053s][info   ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net
[0.053s][info   ][class,load] java.net.SocketOption source: jrt:/java.base
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net
[0.053s][info   ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net
[0.053s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net
[0.054s][info   ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net
[0.054s][info   ][class,load] sun.nio.ch.NioSocketImpl$FileDescriptorCloser source: jrt:/java.base
[0.055s][info   ][class,load] java.net.Socket source: jrt:/java.base

We can switch back to PlainSocketImpl by setting the system property of Djdk.net.usePlainSocketImpl.

D:\test>java -Djdk.net.usePlainSocketImpl -XX:+TraceClassLoading JEP353  | findStr Socket

[0.041s][info   ][class,load] java.net.ServerSocket source: jrt:/java.base
[0.041s][info   ][class,load] jdk.internal.access.JavaNetSocketAccess source: jrt:/java.base
[0.041s][info   ][class,load] java.net.ServerSocket$1 source: jrt:/java.base
[0.041s][info   ][class,load] java.net.SocketOptions source: jrt:/java.base
[0.041s][info   ][class,load] java.net.SocketImpl source: jrt:/java.base
[0.045s][info   ][class,load] java.net.SocketImpl$$Lambda$1/0x0000000800ba0840 source: java.net.SocketImpl
[0.048s][info   ][class,load] sun.net.PlatformSocketImpl source: jrt:/java.base
[0.048s][info   ][class,load] java.net.AbstractPlainSocketImpl source: jrt:/java.base

[0.048s][info   ][class,load] java.net.PlainSocketImpl source: jrt:/java.base

[0.048s][info   ][class,load] java.net.AbstractPlainSocketImpl$1 source: jrt:/java.base
[0.050s][info   ][class,load] sun.net.ext.ExtendedSocketOptions source: jrt:/java.base
[0.050s][info   ][class,load] jdk.net.ExtendedSocketOptions source: jrt:/jdk.net
[0.050s][info   ][class,load] java.net.SocketOption source: jrt:/java.base
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$ExtSocketOption source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.SocketFlow source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$PlatformSocketOptions$1 source: jrt:/jdk.net
[0.051s][info   ][class,load] jdk.net.ExtendedSocketOptions$1 source: jrt:/jdk.net
[0.051s][info   ][class,load] java.net.StandardSocketOptions source: jrt:/java.base
[0.051s][info   ][class,load] java.net.StandardSocketOptions$StdSocketOption source: jrt:/java.base
[0.053s][info   ][class,load] sun.net.ext.ExtendedSocketOptions$$Lambda$2/0x0000000800ba1040 source: sun.net.ext.ExtendedSocketOptions
[0.056s][info   ][class,load] java.net.SocketAddress source: jrt:/java.base
[0.056s][info   ][class,load] java.net.InetSocketAddress source: jrt:/java.base
[0.058s][info   ][class,load] java.net.InetSocketAddress$InetSocketAddressHolder source: jrt:/java.base
[0.059s][info   ][class,load] java.net.SocketCleanable source: jrt:/java.base

4. JEP-354 switch expression (Preview)

The JEP enhances the previous Java 12 JEP 325 Switch expression, Therefore, it can be used as a statement (without returning content) or an expression (returning content). A new keyword "yield" was introduced to return values from switches.

PS this is the preview language function in Java 13

Before the Java 12 traditional switch statement, we can return the following values:

	private static String getText(int number) {
        String result = "";
        switch (number) {
            case 1, 2:
                result = "one or two";
                break;
            case 3:
                result = "three";
                break;
            case 4, 5, 6:
                result = "four or five or six";
                break;
            default:
                result = "unknown";
                break;
        };
        return result;
    }

In Java 12, we can use break to return the value switch.

	private static String getText(int number) {
        String result = switch (number) {
            case 1, 2:
                break "one or two";
            case 3:
                break "three";
            case 4, 5, 6:
                break "four or five or six";
            default:
                break "unknown";
        };
        return result;
    }

In Java 13, the above Java 12 value break is no longer compiled. We should use it yield to return a value.

	private static String getText(int number) {
        return switch (number) {
            case 1, 2:
                yield "one or two";
            case 3:
                yield "three";
            case 4, 5, 6:
                yield "four or five or six";
            default:
                yield "unknown";
        };
    }

switchJava 13 still supports Java 12 rule label or arrow syntax.

	private static String getText(int number) {
        return switch (number) {
            case 1, 2 -> "one or two";
            case 3 -> "three";
            case 4, 5, 6 -> "four or five or six";
            default -> "unknown";
        };
    }

be careful
For a complete example, read this Java 13 switch expression

5. JEP-355 text block (Preview)

The JEP finally introduces multi line string text and text block.

PS this is the preview language function in Java 13

Before Java 13

 String html ="<html>\n" +
			  "   <body>\n" +
			  "      <p>Hello, World</p>\n" +
			  "   </body>\n" +
			  "</html>\n";

			  
 String json ="{\n" +
			  "   \"name\":\"mkyong\",\n" +
			  "   \"age\":38\n" +
			  "}\n";

Now Java 13

 String html = """
                <html>
                    <body>
                        <p>Hello, World</p>
                    </body>
                </html>
				""";

 String json = """
                {
                    "name":"mkyong",
                    "age":38
                }
                """;

To enable Java 13 Preview:

javac --enable-preview --release 13 Example.java
java --enable-preview Example

reference

Posted by renaun on Fri, 26 Nov 2021 05:30:05 -0800