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 语句和表达式的表现力,并新增了处理 NullPointerException
的 null 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 提供了多种字符串组合方式(连接符、StringBuilder
、format()
等)。Java 21 引入的字符串模板通过结合字面文本与模板表达式,提供了更优雅的解决方案。
示例代码:
String name = "Baeldung";
String welcomeText = STR."Welcome to \{name}";
System.out.println(welcomeText);
输出结果:Welcome to Baeldung
模板由三部分组成:
- 模板处理器(如 STR)
- 点号分隔符
- 嵌入表达式(如
\{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
:条目有序的映射
类层次结构更新:
✅ 核心能力:
- 明确定义元素遍历顺序
- 提供首/末元素访问
- 支持前驱/后继操作
2.6. 密钥封装机制 API (JEP 452)
密钥封装是使用非对称加密保护对称密钥的技术。传统方法需要填充,安全性难以证明;而 KEM(密钥封装机制)无需填充即可派生对称密钥。Java 21 新增 KEM API,支持应用使用 KEM 算法。
3. 总结
本文重点解析了 Java 21 的核心改进:
- 记录类模式简化数据解构
- switch 模式匹配提升代码表现力
- 字符串模板优化字符串处理
- 虚拟线程突破并发瓶颈
- 有序集合统一顺序操作
- KEM API 增强密钥管理
其他改进散布在 JDK 各个包中,但上述特性已足够作为探索 Java 21 的起点。完整示例代码可在 GitHub 获取。