Last Updated:

Java 13 中的新功能

银狐
Java 13 徽标

 

Java 13已于 2019 年 9 月 17 日正式发布,请在此处下载 Java 13或此openJDK 存档

Java 13 特性。

Java 13 开发人员功能。

切换表达式(预览)、文本块或多行(预览)

1. JEP 350 动态 CDS 档案

Java 10 引入了JEP 310 应用程序类数据共享。此 JEP 简化了创建 CDS 档案的过程。

此命令创建一个 CDS 存档文件.jar


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

此命令.jar使用现有的 CDS 存档运行。


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

类数据共享 (CDS) 通过创建一次类数据存档并重用它来提高启动性能,这样 JVM 就不需要再次重新创建它。

进一步阅读

 

2. JEP 351 ZGC:取消提交未使用的内存

Java 11 引入了JEP 333: Z Garbage Collector (Experimental);它在清理堆内存时提供了短暂的暂停时间。然而,它并没有将未使用的堆内存返还给操作系统,即使它很长时间没有使用。

该 JEP 通过将未使用的堆内存返回给操作系统来增强 ZGC。

进一步阅读

3. JEP-353 重新实现 Legacy Socket API

的底层实现java.net.Socketjava.net.ServerSocket古追溯到JDK 1.0的遗留Java和C代码的混合,是很难维护和调试。此 JEP 为 Socket API 引入了新的底层实现,这是 Java 13 中的默认实现。

在 Java 13 之前,它使用PlainSocketImplforSocketImpl

ServerSocket.java

public class ServerSocket implements java.io.Closeable {

    /**
     * The implementation of this Socket.
     */
    private SocketImpl impl;

}

Java 13 引入了一个新NioSocketImpl类作为PlainSocketImpl. 但是,如果出现问题,我们仍然可以PlainSocketImpl通过设置jdk.net.usePlainSocketImpl系统属性切换回旧的实现。

查看一个简单的 Socket 示例。

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();
        }

    }
}

在 Java 13 中,默认实现是 NioSocketImpl

终端

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

我们可以PlainSocketImpl通过设置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

PS Java的15 JEP 373:重新实现传统DatagramSocket的API,取代的底层实现java.net.DatagramSocketjava.net.MulticastSocket

进一步阅读

4. JEP-354 开关表达式(预览)

Java 12 引入了JEP 325 Switch 表达式。这个 JEP 放弃break value了支持yieldswitch表达式返回值的关键字。

PS 这是 Java 13 中的预览语言功能

传统的switch语句,我们可以像这样返回一个值:


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

在 Java 12 中,我们可以使用breakswitch.


  private static String getNumberViaBreak(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;
  }

在 Java 13 中,上面的 Java 12value break被删除,以支持yield关键字返回值。


  private static String getNumberViaYield(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";
      };
  }

或者像这样


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

case LJava 13 仍支持规则标签或箭头或。


  private static String getNumberViaCaseL(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";
      };
  }

或者像这样,混合使用箭头语法和yield.


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

PS 此开关表达式成为 Java 14 JEP 361 中的标准功能。

进一步阅读

5. JEP-355 文本块(预览)

这个 JEP 最后引入了一个多行字符串文字,一个文本块。

PS 此文本块是 Java 15 中的永久功能。

在 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";

现在 Java 13


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

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

注意
此文本块在Java 14 – JEP 368 中有第二个预览,添加了两个新的转义序列:

  • \<end-of-line> 抑制线路终止。
  • \s 被翻译成一个空格。

要启用 Java 13 预览功能:


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

进一步阅读

下载源代码

$ git clone https://github.com/mkyong/core-java

$ cd java-13

参考