原创

Java 13 最新特性你知道多少?

JDK 13 于 2019 年 9 月 17 日正式发布。

新版本主要包含五个特性

  • JEP 350: Dynamic CDS Archives
  • JEP 351: ZGC: Uncommit Unused Memory
  • JEP 353: Reimplement the Legacy Socket API
  • JEP 354: Switch Expressions (Preview)
  • JEP 355: Text Blocks (Preview)

Dynamic CDS Archives(动态 CDS 归档)

首先介绍一下 CDS,CDS 全名为 Class Data Sharing,目的是减少Java编程语言应用程序的启动时间,特别是较小的应用程序,并减少内存占用。实现思路是通过JVM调用期间,将共享的归档文件被映射到内存中,从而节省了加载这些类的成本,并允许多个 JVM 进程共享这些类的大部分 JVM 元数据。

JVM 中 CDS 的历史

  • JDK 1.5 引入了CDS 的概念,通过把 rt.jar 中的核心类提前转化成内部表示,转储到一个共享存档(shared archive)中。每个 JVM 只需要装载自己的应用类,启动时间减少了,另外核心类是共享的,所以 JVM 的内存占用也减少了;
  • Oracle JDK 9 中,在支持其他 GC 算法和应用程序类的情况下,这变得非常有用;
  • JDK 10 之前,它一直是一个商业特性,在JDK 10 中它成为了开源的;
  • OpenJDK 13 / JDK 13 中实现了动态 CDS 归档,提高应用程序类数据共享(AppCDS)的可用性。消除了用户为每个应用程序创建类列表而进行试运行的需要。当程序存在时,可以使用 -XX:ArchiveClassesAtExit=<filename>,而不是提供类列表。然后使用 -XX:SharedArchiveFile=<filename>,可以在 JDK 的系统默认存档之上共享类数据

ZGC: Uncommit Unused Memory

ZGC 是在 JDK 11 中引入的,但是到目前为止它还没有像 G1 垃圾收集器那样将未使用的堆内存返回到操作系统。这个 JEP 解决了这个问题,并且默认启用了这个功能。

Reimplement the Legacy Socket API

java.net.Socketjava.net.ServerSocket 的实现非常古老,这个 JEP 为它们引入了新的实现。新的实现方法是 Java 13 中的默认实现,但是旧的实现还没有被删除,可以通过设置系统属性 jdk.net.usePlainSocketImpl 来使用它们。但没有为 java.net.DatagramSocket 引入新的实现。

运行一个实例化 SocketServerSocket 的类将显示这个调试输出。这是默认的(新的实现):

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 是新的实现。

现在让我们设置系统属性并再次运行:

$ 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

它显示了现在使用的旧的实现 java.net.PlainSocketImpl

Switch Expressions (Preview)

在 JDK 12 中引入了 Switch 表达式作为预览特性。JEP 354 修改了这个特性,它引入了 yield 语句来从块中返回值,而不是使用 break。这意味着,switch 表达式(返回值)应该使用 yield,而 switch 语句(不返回值)应该使用 break。

JDK 13 之前的 Switch 的写法:

int i;
switch (x) {
    case "1":
        i = 1;
        break;
    case "2":
        i = 2;
        break;
    default:
        i = x.length();
        break;
}

JDK 13 的 Switch 的写法:

switch (x) {
    case "1" -> 1;
    case "2" -> 2;
    default -> {
        int len = x.length();
        yield len;
    }
}

或者

switch (x) {
    case "1": yield 1;
    case "2": yield 2;
    default: {
        int len = x.length();
        yield len;
    }
}

Text Blocks (Preview)

JDK 12 中引入了 Raw String Literals 特性,但在发布之前就放弃了。JEP 在引入多行字符串文字(一个文本块)方面与此类似。

HTML 例子:

使用字符串文字:

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

使用文本块:

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

SQL 例子

使用字符串文字:

String query = "SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`\n" +
               "WHERE `CITY` = 'INDIANAPOLIS'\n" +
               "ORDER BY `EMP_ID`, `LAST_NAME`;\n";

使用文本块:

String query = """
               SELECT `EMP_ID`, `LAST_NAME` FROM `EMPLOYEE_TB`
               WHERE `CITY` = 'INDIANAPOLIS'
               ORDER BY `EMP_ID`, `LAST_NAME`;
               """;

总结:

以上,就是 JDK 13 中包含的 5 个新特性,能够改变开发者编码风格的主要有 Text BlocksSwitch Expressions 两个新特性,但是这两个特性还处于预览阶段。

而且,JDK 13 并不是 LTS(长期支持)版本,如果你正在使用 Java 8(LTS)或者 Java 11(LTS),暂时可以不必升级到 Java 13。

本文由 Tom 创作,采用 CC BY 3.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。

原文链接:https://blog.sagowiec.com/article/4

该篇文章的评论功能已被站长关闭