1. 概述

Java 16 于 2021 年 3 月 16 日发布,作为继 Java 15 之后的最新短期增量版本。该版本引入了多项实用特性,包括记录类(Records)和密封类(Sealed Classes)。本文将重点解析这些核心改进。

2. 通过代理实例调用默认方法 (JDK-8159746)

Java 16 增强了接口默认方法的支持,现在可通过 java.lang.reflect.InvocationHandler 在动态代理中使用反射调用接口默认方法。来看个简单示例:

interface HelloWorld {
    default String hello() {
        return "world";
    }
}

通过反射在代理实例上调用默认方法:

Object proxy = Proxy.newProxyInstance(getSystemClassLoader(), new Class<?>[] { HelloWorld.class },
    (prox, method, args) -> {
        if (method.isDefault()) {
            return InvocationHandler.invokeDefault(prox, method, args);
        }
        // ...
    }
);
Method method = proxy.getClass().getMethod("hello");
assertThat(method.invoke(proxy)).isEqualTo("world");

3. 时间段支持 (JDK-8247781)

DateTimeFormatter 新增时间段符号 B,提供比传统 am/pm 更友好的时间表述:

LocalTime date = LocalTime.parse("15:25:08.690791");
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h B");
assertThat(date.format(formatter)).isEqualTo("3 in the afternoon");

输出从 3pm 变为 3 in the afternoon。还可使用 BBBBBBBBBB 分别表示短、完整、窄格式。

4. 新增 Stream.toList() 方法 (JDK-8180352)

旨在减少常用 Stream 收集器的样板代码,如 Collectors.toList

List<String> integersAsString = Arrays.asList("1", "2", "3");
List<Integer> ints = integersAsString.stream().map(Integer::parseInt).collect(Collectors.toList());
List<Integer> intsEquivalent = integersAsString.stream().map(Integer::parseInt).toList();

intsEquivalent 实现相同效果且代码更简洁。

5. Vector API 孵化器 (JEP-338)

Vector API 在 Java 16 进入孵化阶段,提供向量计算能力,在支持的 CPU 架构上比传统标量计算性能更优。传统数组乘法:

int[] a = {1, 2, 3, 4};
int[] b = {5, 6, 7, 8};

var c = new int[a.length];

for (int i = 0; i < a.length; i++) {
    c[i] = a[i] * b[i];
}

向量计算版本:

int[] a = {1, 2, 3, 4};
int[] b = {5, 6, 7, 8};

var vectorA = IntVector.fromArray(IntVector.SPECIES_128, a, 0);
var vectorB = IntVector.fromArray(IntVector.SPECIES_128, b, 0);
var vectorC = vectorA.mul(vectorB);
vectorC.intoArray(c, 0);

关键点:

  • 使用 IntVector.fromArray 创建向量
  • SPECIES_128 表示 128 位向量(4 个 int)
  • 特定架构下可优化为单周期计算

注意:孵化阶段 API 可能随版本变化。

6. 记录类 (JEP-395)

记录类在 Java 14 引入,Java 16 带来增量改进。记录类是受限形式的类,用于简洁定义不可变数据对象。

6.1 传统实现方式

public final class Book {
    private final String title;
    private final String author;
    private final String isbn;

    public Book(String title, String author, String isbn) {
        this.title = title;
        this.author = author;
        this.isbn = isbn;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public String getIsbn() {
        return isbn;
    }

    @Override
    public boolean equals(Object o) {
        // ...
    }

    @Override
    public int hashCode() {
        return Objects.hash(title, author, isbn);
    }
}

传统方式存在样板代码多、易出错等问题(如遗漏 equals/hashCode)。

6.2 记录类实现

public record Book(String title, String author, String isbn) {
}

两行代码搞定,简洁高效。

6.3 Java 16 新增特性

现在允许在内部类中定义记录类(Java 15 的 JEP-384 遗漏的限制):

class OuterClass {
    class InnerClass {
        Book book = new Book("Title", "author", "isbn");
    }
}

7. instanceof 模式匹配 (JEP-394)

Java 16 为 instanceof 添加模式匹配支持。传统写法:

Object obj = "TEST";

if (obj instanceof String) {
    String t = (String) obj;
    // do some logic...
}

改进后:

Object obj = "TEST";

if (obj instanceof String t) {
    // do some logic
}

直接在 instanceof 中声明变量,省去强制转换步骤。

8. 密封类 (JEP-397)

密封类在 Java 15 首次引入,用于限定哪些子类可继承父类或实现接口。

8.1 基本用法

public sealed interface JungleAnimal permits Monkey, Snake  {
}

public final class Monkey implements JungleAnimal {
}

public non-sealed class Snake implements JungleAnimal {
}

关键点:

  • sealed + permits 指定允许的子类
  • 子类必须使用以下修饰符:
    • sealed:需指定自己的子类
    • final:禁止继承
    • non-sealed:开放继承

优势:支持穷尽模式匹配,无需 else 处理未知情况:

JungleAnimal j = // some JungleAnimal instance

if (j instanceof Monkey m) {
    // do logic
} else if (j instanceof Snake s) {
    // do logic
}

8.2 Java 16 新增特性

  • sealednon-sealedpermits 识别为上下文关键字(类似 abstract
  • 禁止创建密封类的局部子类(类似禁止匿名子类)
  • 加强密封类及其派生类的类型转换检查

9. 其他重要变更

  • 外部链接器 API:提供灵活的本机代码访问方式(初始支持 C 语言),未来可能扩展到 C++/Fortran,目标是替代 JNI。
  • JDK 内部强封装:默认开启强封装(--illegal-access=permit 参数失效),直接影响依赖 JDK 内部 API 的库和应用(测试场景尤甚)。

10. 总结

本文解析了 Java 16 的核心新特性,包括记录类、密封类、模式匹配等实用改进。完整变更列表请参考 JDK 发行说明。所有示例代码可在 GitHub 获取。


原始标题:New Features in Java 16