1. 概述

本文将探讨 Java 21 中新增的重要特性和改进。作为继 Java 17 之后的最新 LTS 版本,Java 21 于 2023 年 9 月 19 日正式发布,带来了多项令人期待的语言增强。

2. 核心特性解析

2.1. 记录类模式 (JEP 440)

记录类模式在 Java 19 和 20 中作为预览功能出现,现在 Java 21 将其正式转正并进行了优化。该特性扩展了现有的模式匹配功能,支持对记录类实例进行解构,使复杂数据查询更简洁高效,同时新增了嵌套模式支持。

来看个实际例子,代码可以写得更精简:

record Point(int x, int y) {}
    
public static int beforeRecordPattern(Object obj) {
    int sum = 0;
    if(obj instanceof Point p) {
        int x = p.x();
        int y = p.y();
        sum = x+y;
    }
    return sum;
}
    
public static int afterRecordPattern(Object obj) {
    if(obj instanceof Point(int x, int y)) {
        return x+y;
    }
    return 0;
}

这种模式还支持嵌套记录的解构:

enum Color {RED, GREEN, BLUE}
record ColoredPoint(Point point, Color color) {}
record RandomPoint(ColoredPoint cp) {}
public static Color getRamdomPointColor(RandomPoint r) {
    if(r instanceof RandomPoint(ColoredPoint cp)) {
        return cp.color();
    }
    return null;
}

优势:直接访问嵌套记录的属性,代码更直观

2.2. switch 的模式匹配 (JEP 441)

该特性最初在 JDK 17 引入,经过多轮迭代,Java 21 带来了更完善的实现。核心目标是允许在 switch case 标签中使用模式,提升 switch 语句和表达式的表现力,并新增了处理 NullPointerExceptionnull case 标签。

假设有个账户体系:

static class Account{
    double getBalance(){
       return 0;
    }
}

扩展出多种账户类型:

static class SavingsAccount extends Account {
    double getSavings() {
        return 100;
    }
}
static class TermAccount extends Account {
    double getTermAccount() {
        return 1000;
    } 
}
static class CurrentAccount extends Account {
    double getCurrentAccount() {
        return 10000;
    } 
}

在 Java 21 之前,获取余额需要这样写:

static double getBalanceWithOutSwitchPattern(Account account) {
    double balance = 0;
    if(account instanceof SavingsAccount sa) {
        balance = sa.getSavings();
    }
    else if(account instanceof TermAccount ta) {
        balance = ta.getTermAccount();
    }
    else if(account instanceof CurrentAccount ca) {
        balance = ca.getCurrentAccount();
    }
    return balance;
}

⚠️ 问题:if-else 链条冗长,可读性差

Java 21 的模式匹配让代码更简洁:

static double getBalanceWithSwitchPattern(Account account) {
    double result = 0;
    switch (account) {
        case null -> throw new RuntimeException("Oops, account is null");
        case SavingsAccount sa -> result = sa.getSavings();
        case TermAccount ta -> result = ta.getTermAccount();
        case CurrentAccount ca -> result = ca.getCurrentAccount();
        default -> result = account.getBalance();
    };
    return result;
}

验证测试:

SwitchPattern.SavingsAccount sa = new SwitchPattern.SavingsAccount();
SwitchPattern.TermAccount ta = new SwitchPattern.TermAccount();
SwitchPattern.CurrentAccount ca = new SwitchPattern.CurrentAccount();

assertEquals(SwitchPattern.getBalanceWithOutSwitchPattern(sa), SwitchPattern.getBalanceWithSwitchPattern(sa));
assertEquals(SwitchPattern.getBalanceWithOutSwitchPattern(ta), SwitchPattern.getBalanceWithSwitchPattern(ta));
assertEquals(SwitchPattern.getBalanceWithOutSwitchPattern(ca), SwitchPattern.getBalanceWithSwitchPattern(ca));

新特性还支持 when 子句进行条件匹配:

static String processInputNew(String input) {
    String output = null;
    switch(input) {
        case null -> output = "Oops, null";
        case String s when "Yes".equalsIgnoreCase(s) -> output = "It's Yes";
        case String s when "No".equalsIgnoreCase(s) -> output = "It's No";
        case String s -> output = "Try Again";
    }
    return output;
}

优势:避免嵌套 if-else,逻辑更清晰

2.3. 字符串模板 (JEP 430)

Java 提供了多种字符串组合方式(连接符、StringBuilderformat() 等)。Java 21 引入的字符串模板通过结合字面文本与模板表达式,提供了更优雅的解决方案

示例代码:

String name = "Baeldung";
String welcomeText = STR."Welcome to \{name}";
System.out.println(welcomeText);

输出结果:Welcome to Baeldung

String Templates

模板由三部分组成:

  1. 模板处理器(如 STR)
  2. 点号分隔符
  3. 嵌入表达式(如 \{name}

运行时处理器会合并字面文本和表达式值。除了 STR,Java 还提供 FMT 和 RAW 处理器。

2.4. 虚拟线程 (JEP 444)

虚拟线程在 Java 19 作为预览功能引入,Java 21 带来重要更新。虚拟线程是轻量级线程,旨在降低高并发应用的开发复杂度。传统平台线程直接绑定 OS 线程,存在扩展瓶颈;而虚拟线程虽也是 java.lang.Thread 实例,但不固定绑定特定 OS 线程。

使用示例:

try(var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.rangeClosed(1, 10_000).forEach(i -> {
        executor.submit(() -> {
            System.out.println(i);
            try {
                Thread.sleep(Duration.ofSeconds(1));
            } 
            catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
    });
}

🔧 关键改进

  • ✅ 虚拟线程现在始终支持线程局部变量
  • ✅ 通过 Thread.Builder 创建的虚拟线程支持生命周期监控和新线程转储

2.5. 有序集合 (JEP 431)

Java 集合框架中缺乏表示有序元素序列的统一类型。Java 21 新增三个接口解决此问题

  • SequencedCollection:有序集合
  • SequencedSet:无重复元素的有序集合
  • SequencedMap:条目有序的映射

类层次结构更新:

Sequenced Collections

核心能力

  • 明确定义元素遍历顺序
  • 提供首/末元素访问
  • 支持前驱/后继操作

2.6. 密钥封装机制 API (JEP 452)

密钥封装是使用非对称加密保护对称密钥的技术。传统方法需要填充,安全性难以证明;而 KEM(密钥封装机制)无需填充即可派生对称密钥。Java 21 新增 KEM API,支持应用使用 KEM 算法

3. 总结

本文重点解析了 Java 21 的核心改进:

  • 记录类模式简化数据解构
  • switch 模式匹配提升代码表现力
  • 字符串模板优化字符串处理
  • 虚拟线程突破并发瓶颈
  • 有序集合统一顺序操作
  • KEM API 增强密钥管理

其他改进散布在 JDK 各个包中,但上述特性已足够作为探索 Java 21 的起点。完整示例代码可在 GitHub 获取。


原始标题:New Features in Java 21 | Baeldung