JDK 21 LTS 版本重大特性详解
· 阅读需 11 分钟
Java 21 是继 JDK 17 之后的又一个长期支持版本(LTS),于2023年9月19日正式发布。这个版本带来了多个重要特性的正式发布,以及一些新的预览特性。让我们一起深入了解这些新特性。
1. 虚拟线程(正式发布)
虚拟线程终于在 JDK 21 中正式发布,这是 Java 并发编程的一个重大突破:
public class VirtualThreadDemo {
public static void main(String[] args) throws Exception {
// 创建单个虚拟线程
Thread vThread = Thread.startVirtualThread(() -> {
System.out.println("在虚拟线程中运行");
});
// 使用虚拟线程执行器
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交大量任务
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
// 模拟数据库操作
processDatabase(i);
return i;
});
});
}
// 使用结构化并发
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 并行执行多个微服务调用
Future<String> service1 = scope.fork(() -> callMicroservice("service1"));
Future<String> service2 = scope.fork(() -> callMicroservice("service2"));
Future<String> service3 = scope.fork(() -> callMicroservice("service3"));
try {
scope.join(); // 等待所有任务完成
scope.throwIfFailed(); // 如果有任务失败则抛出异常
// 处理结果
processResults(
service1.resultNow(),
service2.resultNow(),
service3.resultNow()
);
} catch (Exception e) {
System.err.println("服务调用失败:" + e.getMessage());
throw e;
}
}
}
// 模拟数据库操作
private static void processDatabase(int id) {
try {
// 模拟网络延迟
Thread.sleep(Duration.ofMillis(100));
System.out.printf("处理数据库记录 %d%n", id);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
// 模拟微服务调用
private static String callMicroservice(String name) throws Exception {
// 模拟网络延迟
Thread.sleep(Duration.ofMillis(200));
return name + " 响应";
}
// 处理微服务结果
private static void processResults(String... results) {
System.out.println("处理服务响应:" + String.join(", ", results));
}
// 展示虚拟线程与平台线程的区别
static void threadComparison() throws Exception {
// 使用平台线程
try (var executor = Executors.newFixedThreadPool(100)) {
// 提交任务...
}
// 使用虚拟线程
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交任务...
}
// 虚拟线程的线程本地变量
ThreadLocal<String> threadLocal = new ThreadLocal<>();
Thread.startVirtualThread(() -> {
threadLocal.set("虚拟线程的值");
System.out.println(threadLocal.get());
}).join();
}
}
主要特点:
- 轻量级线程实现
- 高效的并发处理
- 自动线程管理
- 与现有代码兼容
- 改进的性能和可伸缩性
2. 字符串模板(预览)
引入了字符串模板的预览特性:
public class StringTemplateDemo {
public static void main(String[] args) {
String name = "张三";
int age = 25;
double salary = 12345.67;
// 基本字符串模板
String info = STR."姓名:\{name},年龄:\{age}";
System.out.println(info);
// 格式化数字
String report = STR."员工:\{name},薪资:\{String.format("%.2f", salary)}";
System.out.println(report);
// JSON 模板
String json = STR."""
{
"name": "\{name}",
"age": \{age},
"salary": \{salary},
"department": "技术部",
"skills": ["Java", "Python", "SQL"]
}
""";
System.out.println(json);
// SQL 模板
String sql = STR."""
SELECT *
FROM employees
WHERE name = '\{name}'
AND age >= \{age}
AND salary > \{salary}
""";
System.out.println(sql);
// 条件模板
boolean isAdmin = true;
String role = STR."用户角色:\{isAdmin ? "管理员" : "普通用户"}";
System.out.println(role);
// 表达式模板
int x = 10;
int y = 20;
String calculation = STR."计算结果:\{x} + \{y} = \{x + y}";
System.out.println(calculation);
// HTML 模板
String title = "欢迎页面";
String content = "Hello, World!";
String html = STR."""
<!DOCTYPE html>
<html>
<head>
<title>\{title}</title>
</head>
<body>
<h1>\{title}</h1>
<p>\{content}</p>
<p>生成时间:\{java.time.LocalDateTime.now()}</p>
</body>
</html>
""";
System.out.println(html);
}
// 自定义模板处理器
static String formatJson(StringTemplate template) {
return STR."""
\{template.interpolate()}
""";
}
}
特点:
- 简洁的语法
- 类型安全
- 多行支持
- 表达式支持
- 自定义处理器
3. 记录模式(正式发布)
记录模式匹配正式发布:
public class RecordPatternDemo {
// 基础记录类型
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}
record Circle(Point center, double radius) {}
record Triangle(Point a, Point b, Point c) {}
record ColoredShape(Color color, Shape shape) {}
record Color(int red, int green, int blue) {}
sealed interface Shape permits Circle, Rectangle, Triangle {}
public static void main(String[] args) {
// 创建测试对象
var redCircle = new ColoredShape(
new Color(255, 0, 0),
new Circle(new Point(0, 0), 10)
);
var blueRectangle = new ColoredShape(
new Color(0, 0, 255),
new Rectangle(new Point(0, 0), new Point(5, 5))
);
// 使用记录模式
printShapeInfo(redCircle);
printShapeInfo(blueRectangle);
// 计算形状属性
calculateShapeProperties(redCircle.shape());
calculateShapeProperties(blueRectangle.shape());
}
// 使用记录模式打印形状信息
static void printShapeInfo(ColoredShape coloredShape) {
switch (coloredShape) {
case ColoredShape(
Color(var r, var g, var b),
Circle(Point(var x, var y), var radius)
) -> System.out.printf(
"红:%d 绿:%d 蓝:%d 的圆形,中心在(%d,%d),半径%.1f%n",
r, g, b, x, y, radius
);
case ColoredShape(
Color(var r, var g, var b),
Rectangle(Point(var x1, var y1), Point(var x2, var y2))
) -> System.out.printf(
"红:%d 绿:%d 蓝:%d 的矩形,从(%d,%d)到(%d,%d)%n",
r, g, b, x1, y1, x2, y2
);
case ColoredShape(var color, var shape) ->
System.out.println("其他彩色形状");
}
}
// 计算形状属性
static void calculateShapeProperties(Shape shape) {
switch (shape) {
case Circle(Point(var x, var y), var r) -> {
double area = Math.PI * r * r;
double perimeter = 2 * Math.PI * r;
System.out.printf(
"圆形 - 面积: %.2f, 周长: %.2f%n",
area, perimeter
);
}
case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) -> {
int width = Math.abs(x2 - x1);
int height = Math.abs(y2 - y1);
int area = width * height;
int perimeter = 2 * (width + height);
System.out.printf(
"矩形 - 面积: %d, 周长: %d%n",
area, perimeter
);
}
case Triangle(var p1, var p2, var p3) -> {
// 使用海伦公式计算面积
double a = distance(p1, p2);
double b = distance(p2, p3);
double c = distance(p3, p1);
double s = (a + b + c) / 2;
double area = Math.sqrt(s * (s - a) * (s - b) * (s - c));
System.out.printf("三角形 - 面积: %.2f%n", area);
}
}
}
private static double distance(Point p1, Point p2) {
return Math.sqrt(
Math.pow(p2.x() - p1.x(), 2) +
Math.pow(p2.y() - p1.y(), 2)
);
}
}
改进:
- 完整的类型检查
- 更好的模式组合
- 增强的类型推断
- 与密封类的完美配合
4. 序列集合(正式发布)
新的序列集合 API:
public class SequencedCollectionDemo {
public static void main(String[] args) {
// 序列列表
SequencedCollection<String> fruits = new ArrayList<>();
fruits.addLast("苹果");
fruits.addLast("香蕉");
fruits.addFirst("橙子");
System.out.println("第一个水果:" + fruits.getFirst());
System.out.println("最后一个水果:" + fruits.getLast());
System.out.println("所有水果:" + fruits);
System.out.println("反向顺序:" + fruits.reversed());
// 序列集合
SequencedSet<Integer> numbers = new LinkedHashSet<>();
numbers.addLast(1);
numbers.addLast(2);
numbers.addLast(3);
System.out.println("第一个数字:" + numbers.getFirst());
System.out.println("最后一个数字:" + numbers.getLast());
System.out.println("所有数字:" + numbers);
// 序列映射
SequencedMap<String, Integer> scores = new LinkedHashMap<>();
scores.putLast("张三", 95);
scores.putLast("李四", 88);
scores.putFirst("王五", 92);
System.out.println("第一个成绩:" + scores.firstEntry());
System.out.println("最后一个成绩:" + scores.lastEntry());
System.out.println("所有成绩:" + scores);
System.out.println("反向成绩:" + scores.reversed());
// 使用序列集合进行数据处理
processSequencedCollection();
}
static void processSequencedCollection() {
// 创建一个任务队列
SequencedCollection<Task> tasks = new ArrayDeque<>();
tasks.addLast(new Task("任务1", Priority.HIGH));
tasks.addLast(new Task("任务2", Priority.MEDIUM));
tasks.addLast(new Task("任务3", Priority.LOW));
// 处理任务
while (!tasks.isEmpty()) {
Task task = tasks.removeFirst();
System.out.printf(
"处理任务:%s (优先级:%s)%n",
task.name(), task.priority()
);
}
}
// 任务记录类
record Task(String name, Priority priority) {}
// 优先级枚举
enum Priority { HIGH, MEDIUM, LOW }
}
特点:
- 统一的序列访问
- 双端操作支持
- 反向视图
- 与现有集合兼容
5. 未命名模式和变量(预览)
引入了未命名模式和变量的预览特性:
public class UnnamedPatternsDemo {
public static void main(String[] args) {
// 使用未命名变量
var point = new Point(10, 20);
// 使用未命名模式匹配
if (point instanceof Point(var x, _)) {
System.out.println("x 坐标:" + x);
}
// 在 switch 中使用未命名模式
processShape(new Circle(new Point(0, 0), 5));
processShape(new Rectangle(new Point(0, 0), 10, 20));
}
// 在记录模式中使用未命名模式
static void processShape(Shape shape) {
switch (shape) {
case Circle(Point(var x, _), var radius) ->
System.out.printf("圆形:x=%d, 半径=%.1f%n", x, radius);
case Rectangle(Point(_, var y), var width, _) ->
System.out.printf("矩形:y=%d, 宽度=%d%n", y, width);
}
}
// 在方法参数中使用未命名变量
static void processCoordinates(int x, int _) {
System.out.println("只关心 x 坐标:" + x);
}
// 数据类型定义
record Point(int x, int y) {}
sealed interface Shape permits Circle, Rectangle {}
record Circle(Point center, double radius) implements Shape {}
record Rectangle(Point topLeft, int width, int height) implements Shape {}
}
特点:
- 简化代码
- 提高可读性
- 减少未使用变量
- 更清晰的意图表达
总结
JDK 21 作为一个 LTS 版本,带来了多个重要特性的正式发布,特别是虚拟线程的正式发布标志着 Java 并发编程进入了一个新时代。同时,字符串模板、记录模式等特性的改进也大大提升了开发效率和代码质量。
对于开发者来说,建议:
- 开始在生产环境中使用虚拟线程
- 熟悉并使用新的序列集合 API
- 利用记录模式简化数据处理
- 关注字符串模板等预览特性
- 评估未命名模式和变量的使用场景
作为一个 LTS 版本,JDK 21 将得到长期支持,这些特性将在未来很长一段时间内保持稳定。建议企业用户考虑从之前的 LTS 版本(JDK 17)升级到 JDK 21,以获得这些重要改进带来的好处。