1. 简介

Java 15 于 2020 年 9 月正式发布,是 JDK 平台的下一个短期版本。它在之前版本的基础上进行了一些增强,并引入了多个新特性。

本文将重点介绍 Java 15 的一些关键新特性,以及对开发者有实际意义的其他变化。

2. Records(JEP 384)

Record 是 Java 中一种新的类类型,专门用于创建不可变的数据对象。

Record 最早在 Java 14 中以早期预览的形式引入,Java 15 则进一步优化了其设计,为成为正式特性做准备。

我们先来看一个没有 Record 的传统写法,再看看 Record 是如何简化它的。

2.1. 传统写法(无 Record)

在 Record 出现之前,我们通常这样定义一个不可变的数据传输对象(DTO):

public class Person {
    private final String name;
    private final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

可以看到,为了创建一个简单的不可变对象,我们需要写大量的样板代码:字段必须用 final 修饰,定义全参构造器,为每个字段写 getter 方法。有时候还会加上 final 防止被继承,甚至重写 toStringequalshashCode 方法。

2.2. 使用 Record

使用 Record,我们可以将上面的类简化为:

public record Person(String name, int age) {
}

这个写法有几个关键点:

  • 类定义语法是专门为 Record 设计的;
  • 编译器会自动推断字段并生成构造器、getter、toStringequalshashCode 方法;
  • 不需要手动编写这些样板代码。

当然,Record 也支持我们自定义行为,比如添加校验逻辑:

public record Person(String name, int age) {
    public Person {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数");
        }
    }
}

⚠️ 注意:Record 类是 final 的,不能被继承或声明为 abstract,也不能包含 native 方法。

3. Sealed Classes(JEP 360)

Java 之前对继承的控制粒度较粗,只有 publicprotectedprivate 和包私有等修饰符。

Sealed Classes 的目标是让类或接口显式声明哪些类可以作为其子类或实现类,从而实现更细粒度的控制。

它引入了两个新关键字:sealedpermits

public abstract sealed class Person
    permits Employee, Manager {
 
    //...
}

在这个例子中,Person 类只允许 EmployeeManager 作为其子类:

public final class Employee extends Person {
}

public non-sealed class Manager extends Person {
}

✅ 任何继承 sealed 类的类必须声明为 sealednon-sealedfinal,确保类层次结构是有限且可预测的。

这种有限的类结构对模式匹配(Pattern Matching)非常有帮助:

if (person instanceof Employee) {
    return ((Employee) person).getEmployeeId();
} 
else if (person instanceof Manager) {
    return ((Manager) person).getSupervisorId();
}

没有 Sealed Class 的情况下,编译器无法确定是否覆盖了所有子类,容易导致遗漏。

4. Hidden Classes(JEP 371)

Hidden Classes 是 Java 15 引入的一个新特性,主要用于运行时动态生成不可发现的类

这类类不能被其他类链接,也无法通过反射获取,通常生命周期较短,设计上也更注重加载和卸载效率。

虽然大多数开发者用不到,但对于 JVM 语言或动态字节码操作的场景,Hidden Classes 提供了更安全、更高效的选择。

⚠️ Java 之前的匿名类虽然功能类似,但依赖于 Unsafe API,而 Hidden Classes 不需要。

5. Pattern Matching for instanceof(JEP 375)

Pattern Matching for instanceof 是 Java 14 引入的预览特性,Java 15 继续保持预览状态,未新增功能。

它的目的是简化 instanceof + 强转的样板代码

传统写法:

if (person instanceof Employee) {
    Employee employee = (Employee) person;
    Date hireDate = employee.getHireDate();
    //...
}

使用 Pattern Matching 后:

if (person instanceof Employee employee) {
    Date hireDate = employee.getHireDate();
    //...
}

变量 employee 会在类型检查成功后自动赋值,无需手动强转。

还可以与条件表达式结合使用:

if (person instanceof Employee employee && employee.getYearsOfService() > 5) {
    //...
}

未来版本中,该特性有望扩展到 switch 等更多语法结构中。

6. Foreign Memory Access API(JEP 383)

Foreign Memory Access API 是 Java 14 的孵化特性,Java 15 继续孵化并新增了以下功能:

  • 新增 VarHandle API,支持自定义内存访问;
  • 支持通过 Spliterator 接口并行处理内存段;
  • 增强对 mapped 内存段的支持;
  • 可处理来自本地调用的地址。

Foreign Memory 指的是 JVM 堆外内存,不受 GC 管理,适合处理大块数据,比如缓存、内存映射文件等。

✅ 虽然普通开发者很少直接使用,但对第三方库(如 Netty、Chronicle 等)来说意义重大。

7. 垃圾收集器更新

Java 15 中,ZGC(JEP 377)和 Shenandoah(JEP 379)不再是实验性特性,正式支持使用。

  • 默认 GC 依然是 G1;
  • ZGC 和 Shenandoah 可通过参数启用;
  • Oracle JDK 不包含 Shenandoah,需使用 OpenJDK 或其他厂商版本。

8. 其他重要变化

  • Text Blocks(文本块)在 Java 15 正式支持,告别字符串拼接的痛苦;
  • Helpful NullPointerExceptions(增强空指针提示)默认启用,错误定位更清晰;
  • ⚠️ DatagramSocket API 重写,为 Project Loom 做准备;
  • ✅ 新增对 EdDSA(爱德华曲线数字签名算法) 的支持;
  • Nashorn JavaScript 引擎被移除,GraalVM 成为主流;
  • Biased LockingSolaris/SPARC 端口RMI Activation 被弃用或移除。

9. 总结

Java 15 在继承前几版的基础上,带来了 Record、Sealed Classes、Hidden Classes 等新特性,同时将 ZGC、Shenandoah 等 GC 正式化。

⚠️ Java 15 是短期版本,支持将于 2021 年 3 月结束。之后将迎来 Java 16,再之后就是 LTS 版本 Java 17。

对于有经验的开发者来说,Java 15 是一个值得关注的过渡版本,尤其在语言现代化方面迈出了一大步。


原始标题:New Features in Java 15