Java21值得关注的特性
Java 21 上手:几个真正会改变写法的特性
Java 21 是 2023 年 9 月发布的 LTS。到 2026 年,Java 25 也已经是 LTS 了,但不少团队还停在 21,或者正从 17 往上迁。这个版本的特性不算多,不过有几个会实打实改变日常写法。
虚拟线程:最值得先试
虚拟线程是 Java 21 里最受关注的变化。它把线程的调度从操作系统交给 JVM,创建成本很低,几万个也不心疼。
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10_000; i++) {
executor.submit(() -> {
Thread.sleep(1000);
return null;
});
}
}
这段代码提交了一万个任务,每个睡一秒。换成平台线程,一万个线程不算小数目;虚拟线程则没什么压力。
它适合 I/O 密集的场景,比如调接口、读数据库、等文件。CPU 密集的任务用它没有意义,该用多少核还是多少核。还有两点容易踩:虚拟线程不要池化,用完就扔;Java 21 里在 synchronized 块中做阻塞调用可能钉住载体线程,热点代码可以换成 ReentrantLock。
switch 的模式匹配:少写一摞 if-else
Java 21 把模式匹配 switch 转正了。类型判断、null 处理、条件守卫都能塞进一个 switch:
static String describe(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "正整数 " + i;
case Integer i -> "整数 " + i;
case String s -> "字符串,长度 " + s.length();
case null -> "空值";
default -> "其他类型";
};
}
以前这种逻辑要写一串 if (obj instanceof ...),现在一个表达式解决。when 是守卫条件,case null 也终于合法了。注意 switch 要覆盖所有情况,编译器会检查穷尽性。
记录模式:直接拆对象
记录模式可以在一行里把 record 的字段解构出来,嵌套结构也能拆:
record Point(int x, int y) {}
record Line(Point start, Point end) {}
static void print(Object obj) {
if (obj instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
System.out.printf("(%d,%d) -> (%d,%d)%n", x1, y1, x2, y2);
}
}
配合 switch 用更顺手。以前要层层调用 start().x(),现在模式一写,变量直接到手。record 用得越多,这个特性越省事。
有序集合:first 和 last 有了统一入口
Java 21 新增了 SequencedCollection、SequencedSet、SequencedMap 三个接口。以前取首尾元素,List 用 get(0) 和 get(size()-1),Deque 用 getFirst() 和 getLast(),LinkedHashMap 又是另一套。现在统一了:
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
System.out.println(list.getFirst()); // a
System.out.println(list.getLast()); // c
System.out.println(list.reversed()); // [c, b, a]
SequencedMap 也有 firstEntry()、lastEntry()、reversed()。代码里少一点下标计算,读起来清楚不少。
分代 ZGC:低延迟场景多一个选项
Java 21 给 ZGC 加了分代模式。堆分成年轻代和老年代,短命对象在年轻代回收,整体吞吐和分配效率比非分代版本好一些,暂停时间仍然很短。
启用方式是加两个参数:
-XX:+UseZGC -XX:+ZGenerational
它不是默认选项,适合堆很大、又不想有明显停顿的服务。上生产前还是要压测,别只看宣传里的停顿数字。
还有几个预览特性
Java 21 还带了几项预览特性,需要加 --enable-preview 才能用:
- 字符串模板:
STR."Hello \{name}",拼字符串不用再写一堆加号 - 结构化并发:
StructuredTaskScope,把一组相关任务当成一个整体管理 - 作用域值:
ScopedValue,给线程传递不可变上下文 - 未命名类和实例 main 方法:写个小脚本不用再套
public class
预览特性意味着 API 还可能变,尝鲜可以,别急着上生产。
- 点赞
- 收藏
- 关注作者
评论(0)