Featured image of post Java 21 LTS 版本特性全景:从 Records 到虚拟线程

Java 21 LTS 版本特性全景:从 Records 到虚拟线程

Java 8 → 21 重大特性逐版本解读,涵盖 Lambda/Stream/Record/Switch 模式匹配/虚拟线程/分代 ZGC

Java 21 LTS 版本特性全景:从 Records 到虚拟线程

为什么 LTS 版本对生产至关重要

Java 自 2017 年(Java 9)起改为每 6 个月发版每 3 年一个 LTS(Long-Term Support)。LTS 版本(8/11/17/21)由 Oracle 提供至少 5 年商业支持,是企业生产环境首选。

版本发布年月类型Oracle 维护截止关键特性
Java 82014-03LTS2030-12(延长)Lambda、Stream、Optional、新 Date API
Java 112018-09LTS2026-09HTTP Client、var、ZGC 试验
Java 172021-09LTS2029-09Sealed Class、Pattern Matching、Records(正式)
Java 212023-09LTS2031-09虚拟线程、序列集合、String Templates(预览)、分代 ZGC
Java 252025-09LTS(下一代)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"两步走策略升级。

使用 Hugo 构建
主题 StackJimmy 设计