1. 概述

本教程将围绕 Java 生态系统的新版本 Java SE 17 展开,介绍其新特性、发布流程变化、LTS 支持策略及许可证更新。

2. JEP 列表

先看看那些直接影响开发者日常工作的核心改进:

2.1. 恢复严格浮点语义(JEP 306)

主要面向科学计算场景,强制浮点运算保持严格模式。默认浮点操作均为 strictstrictfp,确保所有平台计算结果一致。

Java 1.2 前本就是默认行为,后因硬件问题调整,需手动加 strictfp 关键字。现在这关键字彻底成历史了。

2.2. 增强伪随机数生成器(JEP 356)

为特殊场景提供新接口和实现,实现算法灵活切换,并优化流式编程支持:

public IntStream getPseudoInts(String algorithm, int streamSize) {
    // 返回指定大小的随机数流(范围0-100)
    return RandomGeneratorFactory.of(algorithm)
            .create()
            .ints(streamSize, 0,100);
}

传统类如 RandomSplittableRandomSecureRandom 现在都实现了新 RandomGenerator 接口。

2.3. 新 macOS 渲染管道(JEP 382)

因 Apple 废弃 OpenGL API(macOS 10.14),Swing 内部改用 Metal API 实现 Java 2D 渲染。现有 API 无需修改。

2.4. macOS/AArch64 移植(JEP 391)

响应 Apple 芯片迁移计划,将 JDK 移植到 macOS AArch64 架构。

2.5. 废弃 Applet API(JEP 398)

浏览器早已移除 Java 插件支持,这个承载着老程序员回忆的 API 正式标记移除(自 Java 9 起已废弃)。

2.6. 强封装 JDK 内部 API(JEP 403)

移除 --illegal-access 标志,彻底阻止访问内部 API(除 sun.misc.Unsafe 等关键类)。平台会忽略该标志并输出废弃提示。

2.7. Switch 模式匹配(预览)(JEP 406)

增强 switch 表达式能力,减少样板代码:

static record Human (String name, int age, String profession) {}

public String checkObject(Object obj) {
    return switch (obj) {
        case Human h -> "Name: %s, age: %s and profession: %s".formatted(h.name(), h.age(), h.profession());
        case Circle c -> "This is a circle";
        case Shape s -> "It is just a shape";
        case null -> "It is null";
        default -> "It is an object";
    };
}

public String checkShape(Shape shape) {
    return switch (shape) {
        case Triangle t && (t.getNumberOfSides() != 3) -> "This is a weird triangle";
        case Circle c && (c.getNumberOfSides() != 0) -> "This is a weird circle";
        default -> "Just a normal shape";
    };
}

2.8. 移除 RMI 激活机制(JEP 407)

Java 15 已标记移除,本版本彻底删除此 API。

2.9. 密封类(JEP 409)

Project Amber 产物,限制类/接口的继承实现范围。配合模式匹配实现更优雅的类型检查:

int getNumberOfSides(Shape shape) {
    return switch (shape) {
        case WeirdTriangle t -> t.getNumberOfSides();
        case Circle c -> c.getNumberOfSides();
        case Triangle t -> t.getNumberOfSides();
        case Rectangle r -> r.getNumberOfSides();
        case Square s -> s.getNumberOfSides();
    };
}

2.10. 移除实验性 AOT/JIT 编译器(JEP 410)

GraalVM 的实验性编译器因维护成本高且使用率低被移除,仍可通过 GraalVM 独立使用。

2.11. 废弃安全管理器(JEP 411)

客户端安全机制已无实际意义,标记移除。

2.12. 外部函数与内存 API(孵化器)(JEP 412)

替代 JNI,安全调用 JVM 外代码并管理堆外内存。Project Panama 产物:

private static final SymbolLookup libLookup;

static {
    // 加载 C 库
    var path = JEP412.class.getResource("/print_name.so").getPath();
    System.load(path);
    libLookup = SymbolLookup.loaderLookup();
}

调用示例:

public String getPrintNameFormat(String name) {
    var printMethod = libLookup.lookup("printName");

    if (printMethod.isPresent()) {
        var methodReference = CLinker.getInstance()
            .downcallHandle(
                printMethod.get(),
                MethodType.methodType(MemoryAddress.class, MemoryAddress.class),
                FunctionDescriptor.of(CLinker.C_POINTER, CLinker.C_POINTER)
            );

        try {
            var nativeString = CLinker.toCString(name, newImplicitScope());
            var invokeReturn = methodReference.invoke(nativeString.address());
            var memoryAddress = (MemoryAddress) invokeReturn;
            return CLinker.toJavaString(memoryAddress);
        } catch (Throwable throwable) {
            throw new RuntimeException(throwable);
        }
    }
    throw new RuntimeException("printName function not found.");
}

2.13. 向量 API(第二孵化器)(JEP 414)

利用 CPU SIMD 指令优化并行计算,适合科学计算、图像处理等场景:

public void newVectorComputation(float[] a, float[] b, float[] c) {
    for (var i = 0; i < a.length; i += SPECIES.length()) {
        var m = SPECIES.indexInRange(i, a.length);
        var va = FloatVector.fromArray(SPECIES, a, i, m);
        var vb = FloatVector.fromArray(SPECIES, b, i, m);
        var vc = va.mul(vb);
        vc.intoArray(c, i, m);
    }
}

public void commonVectorComputation(float[] a, float[] b, float[] c) {
    for (var i = 0; i < a.length; i ++) {
        c[i] = a[i] * b[i];  // 传统实现
    }
}

2.14. 上下文特定反序列化过滤器(JEP 415)

扩展 JEP 290,支持 JVM 级别的动态反序列化过滤器,增强安全性。

3. LTS 定义

发布模式迎来重大变革:

3.1. 六个月功能发布模式

新模式让功能"成熟即发布",避免功能积压。 开发者无需苦等三四年,用户也能更快试用预览特性并提供反馈。

3.2. LTS 模式

企业应用需要稳定支持,因此推出 LTS 版本:

  • Oracle 提供 8 年支持(修复 + 安全补丁)
  • 当前 LTS 版本:Java 11(2018.9)、Java 17(2021.9)
  • 重大调整:LTS 间隔从 3 年缩至 2 年,Java 21(2023.9)将是下个 LTS

此模式借鉴了 Firefox/Ubuntu 等成功经验。

4. 新发布流程

基于 JEP 3,核心流程如下:

4.1. 新格式

发布周期分三阶段(总长约 3 个月):

  1. 分支阶段:从主仓库 fork 出 JDK/JDK$N 分支(如 JDK17),停止接受新 JEP
  2. 稳定阶段
    • 降级阶段 1(4-5周):仅处理当前 P1-P3 和目标 P1-P2 缺陷
    • 降级阶段 2(3-4周):仅处理当前 P1-P2 和目标 P1 缺陷
  3. 候选发布(2-5周):仅修复关键 P1 缺陷

术语说明:

  • 缺陷分类
    • Current:当前版本相关缺陷/新特性调整
    • Targeted:历史版本遗留问题
  • 优先级:P1(最高)→ P5(最低)

5. 接下来是什么?

  • JDK 18(2022.3):无重大变更,关注 OpenJDK 官网
  • 许可证更新:Oracle JDK 采用 免费条款(生产环境仍有限制)
  • 下个 LTS:Java 21(2023.9)按计划推进

6. 结论

本文梳理了 Java 17 的核心改进、发布模式变革及未来规划。所有示例代码可在 GitHub 获取。作为 LTS 版本,Java 17 将成为企业应用的稳健选择。


原始标题:New Features in Java 17