Java 13中的新功能
1. 概述
根据 Java 六个月的新发布节奏,2019 年 9 月发布了 JDK 13。在本文中,我们将了解此版本中引入的新功能和改进。
2. 预览开发者功能
Java 13 带来了两个新的语言特性,尽管是在预览模式下。这意味着这些功能已完全实现,供开发人员评估,但尚未准备好生产。此外,它们可以根据反馈在未来的版本中删除或永久保留。 我们需要将–enable-preview*指定为命令行标志才能使用预览功能*。让我们深入了解一下。
2.1. 切换表达式 (JEP 354)
我们最初在JDK 12 中看到了 switch 表达式。Java 13 的switch表达式 通过添加新的yield语句构建在先前版本的基础上。 使用yield,我们现在可以有效地从 switch 表达式返回值:
@Test
@SuppressWarnings("preview")
public void whenSwitchingOnOperationSquareMe_thenWillReturnSquare() {
var me = 4;
var operation = "squareMe";
var result = switch (operation) {
case "doubleMe" -> {
yield me * 2;
}
case "squareMe" -> {
yield me * me;
}
default -> me;
};
assertEquals(16, result);
}
正如我们所看到的,现在很容易使用新的switch 来实现策略模式 。
2.2. 文本块 ( JEP 355 )
第二个预览功能是嵌入JSON、XML、HTML等多行String的文本块 。 早些时候,为了在我们的代码中嵌入 JSON,我们会将其声明为String文字:
String JSON_STRING
= "{\r\n" + "\"name\" : \"Blogdemo\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}";
现在让我们使用String文本块编写相同的 JSON :
String TEXT_BLOCK_JSON = """
{
"name" : "Blogdemo",
"website" : "https://www.%s.com/"
}
""";
很明显,无需转义双引号或添加回车。通过使用文本块,嵌入式 JSON 编写起来更简单,也更易于阅读和维护。
此外,所有String函数都可用:
@Test
public void whenTextBlocks_thenStringOperationsWorkSame() {
assertThat(TEXT_BLOCK_JSON.contains("Blogdemo")).isTrue();
assertThat(TEXT_BLOCK_JSON.indexOf("www")).isGreaterThan(0);
assertThat(TEXT_BLOCK_JSON.length()).isGreaterThan(0);
}
此外,java.lang.String现在具有三种操作文本块的新方法:
- stripIndent() – 模仿编译器删除附带的空白
- translateEscapes() – 将转义序列如*“\t”翻译成“\t”*
- formatted() – 与 String::format相同,但用于文本块
让我们快速看一下String::formatted示例:
assertThat(TEXT_BLOCK_JSON.formatted("blogdemo").contains("www.blogdemo.com")).isTrue();
assertThat(String.format(JSON_STRING,"blogdemo").contains("www.blogdemo.com")).isTrue();
由于文本块是预览功能,可以在未来的版本中删除,因此这些新方法已标记为弃用。
3. 动态 CDS 档案 (JEP 350)
一段时间以来,类数据共享 (CDS) 一直是 Java HotSpot VM 的一个突出特性。它允许在不同的 JVM 之间共享类元数据,以减少启动时间和内存占用。JDK 10 通过添加应用程序 CDS ( AppCDS ) 扩展了这种能力——让开发人员能够将应用程序类包含在共享存档中。JDK 12 进一步增强了此功能 ,默认包含CDS 存档。
然而,归档应用程序类的过程是乏味的。要生成存档文件,开发人员必须先试运行他们的应用程序以创建类列表,然后将其转储到存档中。之后,这个存档可用于在 JVM 之间共享元数据。 通过动态归档 ,JDK 13 简化了这个过程。现在我们可以在应用程序退出时生成共享存档。这消除了试运行的需要。 为了使应用程序能够在默认系统存档之上创建动态共享存档,我们需要添加一个选项*-XX:ArchiveClassesAtExit* 并将存档名称指定为参数:
java -XX:ArchiveClassesAtExit=<archive filename> -cp <app jar> AppName
然后我们可以使用新创建的存档来运行带有*-XX:SharedArchiveFile* 选项的相同应用程序:
java -XX:SharedArchiveFile=<archive filename> -cp <app jar> AppName
4. ZGC:取消提交未使用的内存 (JEP 351)
Z Garbage Collector 是在 Java 11 中引入的一种低延迟垃圾收集机制,因此 GC 暂停时间永远不会超过 10 毫秒。然而,与 G1 和 Shenandoah 等其他 HotSpot VM GC 不同,它无法将未使用的堆内存返回给操作系统。Java 13 将此功能添加 到 ZGC。 我们现在减少了内存占用并提高了性能。 从 Java 13 开始,ZGC 现在默认将未提交的内存返回给操作系统,直到达到指定的最小堆大小。如果我们不想使用这个特性,我们可以通过以下方式回到 Java 11 的方式:
- 使用选项*-XX:-ZUncommit,*或
- 设置相等的最小 ( -Xms ) 和最大 ( -Xmx ) 堆大小 此外,ZGC 现在支持的最大堆大小为 16TB。早些时候,4TB 是极限。
5. 重新实现遗留套接字 API (JEP 353)
自 Java 诞生以来,我们就已经看到 Socket(java.net.Socket和java.net.ServerSocket)API 作为 Java 不可或缺的一部分。然而,它们在过去二十年中从未进行过现代化改造。它们是用遗留的 Java 和 C 编写的,既麻烦又难以维护。 Java 13 逆势而行,替换了底层实现 ,使 API 与未来的用户模式线程保持一致。提供者接口现在指向NioSocketImpl而不是PlainSocketImpl。这个新编码的实现基于与java.nio相同的内部基础结构。 同样,我们确实有办法返回使用PlainSocketImpl。我们可以通过将系统属性*-Djdk.net.usePlainSocketImpl设置为true来启动 JVM ,以使用旧的实现。默认是NioSocketImpl*。
6. 杂项变更
除了上面列出的 JEP 之外,Java 13 还为我们提供了一些更显着的变化:
- java.nio – 方法*FileSystems.newFileSystem(Path, Map<String, ?>)*添加
- java.time – 添加了新的官方日本时代名称
- javax.crypto – 支持 MS 下一代密码术 (CNG)
- javax.security –添加属性jdk.sasl.disabledMechanisms以禁用 SASL 机制
- javax.xml.crypto –引入新的字符串常量来表示 Canonical XML 1.1 URI
- javax.xml.parsers – 添加了新方法来实例化具有命名空间支持的 DOM 和 SAX 工厂
- Unicode 支持升级到版本 12.1
- 添加了对 Kerberos 主体名称规范化和跨领域引用的支持
此外,还建议删除 一些 API 。其中包括上面列出的三个String方法和javax.security.cert API。 删除的内容包括rmic工具和JavaDoc 工具的旧功能 。JDK 1.4 之前的SocketImpl实现也不再受支持。