Java 21 LTS 版本特性全景:从 Records 到虚拟线程
为什么 LTS 版本对生产至关重要
Java 自 2017 年(Java 9)起改为每 6 个月发版、每 3 年一个 LTS(Long-Term Support)。LTS 版本(8/11/17/21)由 Oracle 提供至少 5 年商业支持,是企业生产环境首选。
| 版本 | 发布年月 | 类型 | Oracle 维护截止 | 关键特性 |
|---|
| Java 8 | 2014-03 | LTS | 2030-12(延长) | Lambda、Stream、Optional、新 Date API |
| Java 11 | 2018-09 | LTS | 2026-09 | HTTP Client、var、ZGC 试验 |
| Java 17 | 2021-09 | LTS | 2029-09 | Sealed Class、Pattern Matching、Records(正式) |
| Java 21 | 2023-09 | LTS | 2031-09 | 虚拟线程、序列集合、String Templates(预览)、分代 ZGC |
| Java 25 | 2025-09 | LTS(下一代) | 2033+ | 待定 |
本文按版本时序梳理 8 → 21 的核心特性,重点展开 17/21 两个 LTS 的"必须升级"理由。
Java 8(2014-03):函数式编程革命
Lambda 表达式
1
2
3
4
5
6
7
8
9
10
| // 旧写法:匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
};
// 新写法:Lambda
Runnable r2 = () -> System.out.println("hello");
|
Stream API
1
2
3
4
5
| List<String> result = users.stream()
.filter(u -> u.getAge() >= 18)
.map(User::getName)
.sorted()
.collect(Collectors.toList());
|
Optional 抗 NPE
1
2
| Optional<User> user = userRepo.findById(id);
String name = user.map(User::getName).orElse("anonymous");
|
新 Date/Time API(java.time)
替代 java.util.Date / SimpleDateFormat(线程不安全)。
Java 11(2018-09):HTTP Client + var
var 局部变量类型推断
1
2
| var list = new ArrayList<String>(); // 推断为 ArrayList<String>
var stream = list.stream(); // 推断为 Stream<String>
|
标准 HTTP Client
1
2
3
4
5
6
7
| HttpClient client = HttpClient.newHttpClient();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString());
|
字符串新方法
isBlank() / strip() / repeat(n) / lines()。
Java 17(2021-09):Records + Sealed + Pattern Matching
Record(不可变数据载体)
1
2
3
4
5
6
7
8
9
10
11
12
| // 旧写法:30 行 POJO
public class User {
private final Long id;
private final String name;
public User(Long id, String name) { this.id = id; this.name = name; }
public Long getId() { return id; }
public String getName() { return name; }
// equals/hashCode/toString ...
}
// 新写法:1 行
public record User(Long id, String name) {}
|
Sealed Class(封闭类)
1
2
3
4
5
6
| public sealed interface Shape permits Circle, Rectangle, Triangle {
double area();
}
public record Circle(double radius) implements Shape {
public double area() { return Math.PI * radius * radius; }
}
|
编译器在 switch Pattern Matching 时能做穷尽性检查:
1
2
3
4
5
6
| double total = switch (shape) {
case Circle c -> c.area();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
// 无需 default,编译器保证穷尽
};
|
Text Blocks(Java 13 引入、15 正式)
1
2
3
4
5
| String html = """
<html>
<body>Hello</body>
</html>
""";
|
Pattern Matching for instanceof(Java 16 正式)
1
2
3
4
5
6
7
8
9
| // 旧写法
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// 新写法
if (obj instanceof String s) {
System.out.println(s.length());
}
|
Java 21(2023-09):下一代 LTS
Java 21 是 Java 8 以来最值得升级的 LTS。三大核心:虚拟线程、序列集合、分代 ZGC。
1. 虚拟线程(Virtual Threads,JEP 444)
问题:传统平台线程 1:1 映射 OS 线程,1MB 栈空间 × 10000 并发 = 10GB 内存。
方案:虚拟线程由 JVM 调度到少量 OS 线程(M:N),内存占用从 MB 降到 KB,百万级并发成为可能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // 创建方式 1:Thread.ofVirtual()
Thread vt = Thread.ofVirtual().name("vt-1").start(() -> {
System.out.println("running in virtual thread");
});
// 创建方式 2:Thread.startVirtualThread()
Thread.startVirtualThread(() -> callExternalApi());
// 创建方式 3:ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofMillis(100));
return i;
});
});
}
|
对 Web 框架的影响:
- Spring Boot 3.2+ 内置
spring.threads.virtual.enabled=true - Tomcat 默认线程池切换到虚拟线程,10K 并发连接用 1 个平台线程即可
- 注意:避免在虚拟线程中使用
synchronized(pin 住平台线程),改用 ReentrantLock
2. 序列集合(Sequenced Collections,JEP 431)
新接口统一 List / Deque / SortedSet 的"首尾"操作:
1
2
3
4
5
6
7
8
9
10
11
12
| List<String> list = new ArrayList<>(List.of("a", "b", "c"));
// 旧写法(要记 addFirst 还是 add(0, e))
list.add(0, "first");
String first = list.get(0);
// 新写法
list.addFirst("first");
String head = list.getFirst();
String tail = list.getLast();
list.removeLast();
List<String> reversed = list.reversed(); // 反转视图
|
3. Switch 模式匹配(Pattern Matching for switch,JEP 441)
Java 21 正式版,覆盖 Java 17 的类型模式 + 守卫模式:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| // 带 when 守卫
String format(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "正整数: " + i;
case Integer i -> "非正整数: " + i;
case Long l -> "Long: " + l;
case String s -> "字符串: " + s;
case null -> "null";
default -> obj.toString();
};
}
// null 模式(Java 21 新增)
switch (obj) {
case null -> System.out.println("null safe");
case String s -> System.out.println("string: " + s);
default -> System.out.println("other");
}
|
4. Record Patterns(记录模式,JEP 440)
1
2
3
4
5
6
7
8
9
10
11
| record Point(int x, int y) {}
record Segment(Point start, Point end) {}
// 解构
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) -> "点(" + x + ", " + y + ")";
case Segment(Point s, Point e) -> "线段: " + s + " → " + e;
default -> "其他";
};
}
|
5. 字符串模板(String Templates,JEP 459 预览)
1
2
3
4
5
| // 旧写法
String msg = "User " + user.name() + " (id=" + user.id() + ") scored " + score;
// 新写法
String msg = STR."User \{user.name()} (id=\{user.id()}) scored \{score}";
|
支持自定义模板处理器(STR / FMT / RAW),可用于 SQL 安全拼接、HTML 转义等。
6. 未命名类和实例主方法(JEP 445)
简化 Hello World 写法(被网友调侃"卵用不大"):
1
2
3
4
5
6
7
8
9
10
11
| // Java 8 写法
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
// Java 21 写法
void main() {
System.out.println("Hello, World!");
}
|
7. 分代 ZGC(Generational ZGC,JEP 439)
问题:传统 ZGC 把年轻代老年代同等对待,浪费性能。
方案:分代 ZGC 区分新生代(短命对象)和老年代(长命对象),新生代用更激进的收集策略。
启用:
1
| java -XX:+UseZGC -XX:+ZGenerational MyApp
|
升级路径建议
从 Java 8 → 17
| 风险 | 缓解 |
|---|
Sun 内部 API 移除(sun.misc.*) | 替换为公共 API 或加 --add-exports 临时绕过 |
| Nashorn JavaScript 引擎移除 | 改用 GraalVM JavaScript |
强封装 JDK 内部(--illegal-access 默认为 deny) | 加 --add-opens |
| CMS 收集器移除 | 改用 G1(默认)或 ZGC |
从 Java 17 → 21
升级成本低(向下兼容),主要工作是开启虚拟线程:
1
2
3
4
5
| # application.yml
spring:
threads:
virtual:
enabled: true # Spring Boot 3.2+ 一键开启
|
然后排查代码中的 synchronized 块(pin 住平台线程),改用 ReentrantLock。
LTS 选择决策树
1
2
3
4
5
6
| 项目周期 < 1 年?
├── 是 → 选最新非 LTS(用新特性)
└── 否
├── 2024 启动 → 选 Java 17(生态成熟)
├── 2024 启动 + 大量并发连接 → 选 Java 21(虚拟线程)
└── 2026+ 启动 → 选 Java 21 / 等 Java 25(2025-09 LTS)
|
小结
Java 21 是 Java 8 以来最值得升级的 LTS。虚拟线程 + 分代 ZGC 让 Java 在高并发 / 云原生场景下重新具备竞争力;Record + Sealed + Pattern Matching 让 Java 进入"数据导向编程"新范式。建议所有新项目直接基于 Java 21,老项目(Java 8/11)按"先 17 再 21"两步走策略升级。