1. 概述

2019年9月,JDK 13 正式发布,延续了Java每六个月一次的发布节奏。本文将深入解析该版本引入的核心新特性与改进点,帮助开发者快速掌握关键变化。

2. 预览版语言特性

Java 13 引入了两个处于“预览”状态的语言特性。这意味着它们功能完整、可用于评估,但尚未正式生产就绪。未来版本可能根据社区反馈决定是否保留或转正。

⚠️ 要使用这些预览功能,必须在编译和运行时显式添加 --enable-preview 命令行参数。

2.1. Switch 表达式(JEP 354)

Switch 表达式最早出现在 JDK 12 中,而 Java 13 在其基础上引入了全新的 yield 关键字,用于从 switch 块中返回值。

✅ 使用 yield 后,switch 不再局限于 breakreturn,逻辑更清晰,也更容易实现类似策略模式的结构:

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

📌 踩坑提示:yield 只能在 case{} 块中使用,不能用于箭头语法(->)直接表达的单行语句。

2.2. 文本块(Text Blocks,JEP 355)

这是 Java 13 最受欢迎的预览特性之一,专为处理多行字符串设计,比如嵌入 JSON、XML、HTML 等内容。

❌ 以往写法繁琐且易错:

String JSON_STRING 
  = "{\r\n" + "\"name\" : \"Baeldung\",\r\n" + "\"website\" : \"https://www.%s.com/\"\r\n" + "}";

✅ 使用文本块后,代码简洁直观,无需转义引号或手动换行:

String TEXT_BLOCK_JSON = """
{
    "name" : "Baeldung",
    "website" : "https://www.%s.com/"
}
""";

所有 String 的方法依然可用:

@Test
public void whenTextBlocks_thenStringOperationsWorkSame() {        
    assertThat(TEXT_BLOCK_JSON.contains("Baeldung")).isTrue();
    assertThat(TEXT_BLOCK_JSON.indexOf("www")).isGreaterThan(0);
    assertThat(TEXT_BLOCK_JSON.length()).isGreaterThan(0);
}

此外,String 类新增了三个专为文本块设计的方法:

  • stripIndent():自动去除每行前导空格(编译器级智能去缩进)
  • translateEscapes():将转义序列如 \\t 解析为 \t
  • formatted(...):等价于 String.format,但专为文本块设计

示例:使用 formatted 动态填充域名

assertThat(TEXT_BLOCK_JSON.formatted("baeldung").contains("www.baeldung.com")).isTrue();
assertThat(String.format(JSON_STRING,"baeldung").contains("www.baeldung.com")).isTrue();

⚠️ 注意:由于文本块仍为预览特性,上述新方法在 JDK 13 中被标记为 **@Deprecated(forRemoval = true)**,意为未来可能移除。

3. 动态 CDS 归档(JEP 350)

CDS(Class Data Sharing)是 HotSpot VM 的经典优化手段,通过共享类元数据来降低 JVM 启动时间和内存占用。JDK 10 引入了 AppCDS,允许将应用类加入共享归档;JDK 12 默认启用系统级 CDS 归档。

但传统流程太麻烦:必须先试运行应用生成类列表,再手动导出归档文件,步骤繁琐且容易出错。

Java 13 的 动态 CDS 归档解决了这个问题——应用退出时自动将已加载的类写入归档文件,省去了预运行步骤。

使用方式简单粗暴:

  1. 第一次运行时启用归档生成:
java -XX:ArchiveClassesAtExit=myapp.jsa -cp myapp.jar com.example.Main
  1. 后续运行直接加载归档:
java -XX:SharedArchiveFile=myapp.jsa -cp myapp.jar com.example.Main

✅ 效果:显著提升微服务冷启动速度,尤其适合容器化部署场景。

4. ZGC:释放未使用内存(JEP 351)

ZGC(Z Garbage Collector)自 Java 11 起作为低延迟 GC 方案登场,承诺 GC 停顿时间不超过 10ms。但早期版本有个硬伤:无法将空闲堆内存归还给操作系统,导致长期运行服务内存“只增不减”。

Java 13 为 ZGC 补上了这块拼图:

ZGC 现在默认会将未提交的堆内存释放回操作系统,直到达到 -Xms 设置的最小堆大小。

如果不想启用此功能,有两种方式回退到 Java 11 行为:

  • 使用 -XX:-ZUncommit
  • 设置 -Xms-Xmx 相等(禁用堆动态伸缩)

此外,ZGC 最大堆支持从 4TB 提升至 16TB,进一步拓宽了其在超大内存场景下的适用性。

5. 重构遗留 Socket API(JEP 353)

java.net.SocketServerSocket 是 Java 最古老的 API 之一,底层由陈旧的 Java/C 混合代码实现,维护困难,且与现代 NIO 架构脱节。

Java 13 将其底层实现从 PlainSocketImpl 替换为基于 java.nioNioSocketImpl,带来以下好处:

  • ✅ 更简洁的代码结构
  • ✅ 更好的可维护性
  • ✅ 为未来支持虚拟线程(Virtual Threads)铺路

⚠️ 兼容性考虑:可通过 JVM 参数切换回旧实现:

-Djdk.net.usePlainSocketImpl=true

默认值为 false,即使用新的 NioSocketImpl

6. 其他重要变更

除上述 JEP 外,Java 13 还包含多项实用改进:

新增 API

  • java.nio:新增 FileSystems.newFileSystem(Path, Map<String, ?>),简化文件系统挂载
  • java.time:支持日本新年号「令和」(Reiwa)
  • javax.crypto:支持 Windows 的 CNG(Cryptography Next Generation)加密框架
  • javax.security:新增 jdk.sasl.disabledMechanisms 属性,用于禁用特定 SASL 认证机制
  • javax.xml.crypto:新增 Canonical XML 1.1 的 URI 常量
  • javax.xml.parsers:支持带命名空间的 DOM/SAX 工厂实例化

基础设施升级

  • Unicode 升级至 12.1 版本
  • Kerberos 支持主体名称规范化和跨域跳转(cross-realm referrals)

已标记待移除的 API

以下 API 已被标记为废弃,未来版本可能移除:

  • 三个 String 方法(与文本块冲突)
  • javax.security.cert
  • rmic 工具(RMI 编译器)
  • Javadoc 工具中的老旧功能
  • 所有 JDK 1.4 之前的 SocketImpl 自定义实现

7. 总结

Java 13 虽然没有引入革命性语法变更,但在性能优化、API 现代化和开发者体验上做了扎实改进。特别是:

  • 文本块极大简化了多行字符串处理
  • 动态 CDS 降低了应用启动开销
  • ZGC 内存回收让低延迟 GC 更加实用
  • Socket 重构为未来虚拟线程打下基础

尽管部分特性仍处于预览阶段,但已足够在非生产环境尝试。建议开发者结合 --enable-preview 在新项目中体验这些特性,为未来升级做好准备。

所有示例代码已托管至 GitHub:https://github.com/baeldung/tutorials/tree/master/core-java-modules/core-java-13


原始标题:New Features in Java 13