掌握Java 21 LTS版本的最新特性:虚拟线程、模式匹配增强、字符串模板等
Java 21是Oracle在2023年9月发布的长期支持(LTS)版本,继Java 17之后的又一个重要里程碑。作为LTS版本,Java 21将获得长期的支持和维护,是企业级应用的理想选择。
Java 21引入了多项革命性特性,特别是虚拟线程的正式发布,极大地简化了并发编程。同时,模式匹配、字符串模板等特性让代码更加简洁和表达力更强。
// 创建虚拟线程
Thread virtualThread = Thread.ofVirtual()
.name("virtual-thread-1")
.start(() -> {
System.out.println("运行在虚拟线程中");
});
// 使用虚拟线程执行器
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
executor.submit(() -> {
// 任务代码
return "虚拟线程执行结果";
});
}
// 模式匹配with switch
String result = switch (obj) {
case String s -> "字符串: " + s;
case Integer i -> "整数: " + i;
case List> list -> "列表大小: " + list.size();
case null -> "空值";
default -> "未知类型";
};
// 守卫条件
String classify = switch (obj) {
case String s when s.length() > 10 -> "长字符串";
case String s -> "短字符串";
case Integer i when i > 0 -> "正整数";
case Integer i -> "非正整数";
default -> "其他类型";
};
// 字符串模板基本用法
String name = "张三";
int age = 25;
String message = STR."你好,\{name}!你今年\{age}岁了。";
// 表达式插值
int x = 10, y = 20;
String calculation = STR."\{x} + \{y} = \{x + y}";
// 多行字符串模板
String html = STR."""
\{title}
\{content}
""";
// SequencedCollection接口
List list = new ArrayList<>();
list.addFirst("第一个");
list.addLast("最后一个");
String first = list.getFirst();
String last = list.getLast();
// SequencedSet接口
LinkedHashSet set = new LinkedHashSet<>();
set.addFirst(1);
set.addLast(3);
SequencedSet reversed = set.reversed();
// SequencedMap接口
LinkedHashMap map = new LinkedHashMap<>();
map.putFirst("first", 1);
map.putLast("last", 100);
Entry firstEntry = map.firstEntry();
虚拟线程是Java 21最重要的特性之一,它们是轻量级的线程,由JVM管理而不是操作系统。虚拟线程使得编写高并发应用程序变得更加简单。
特性 | 平台线程 | 虚拟线程 |
---|---|---|
创建成本 | 高(约2MB栈空间) | 低(几KB) |
最大数量 | 数千个 | 数百万个 |
调度方式 | 操作系统调度 | JVM调度 |
阻塞行为 | 阻塞OS线程 | 不阻塞载体线程 |
适用场景 | CPU密集型任务 | I/O密集型任务 |
public class VirtualThreadExample {
public static void main(String[] args) throws Exception {
System.out.println("=== Java 21 虚拟线程示例 ===");
basicVirtualThread();
virtualThreadExecutor();
performanceComparison();
}
private static void basicVirtualThread() throws InterruptedException {
System.out.println("\n--- 基本虚拟线程 ---");
Thread virtualThread = Thread.ofVirtual()
.name("virtual-worker")
.start(() -> {
System.out.println("虚拟线程: " + Thread.currentThread());
System.out.println("是否为虚拟线程: " + Thread.currentThread().isVirtual());
System.out.println("线程名称: " + Thread.currentThread().getName());
try {
Thread.sleep(Duration.ofMillis(500));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("虚拟线程完成任务");
});
virtualThread.join();
}
private static void virtualThreadExecutor() throws Exception {
System.out.println("\n--- 虚拟线程执行器 ---");
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
List> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int taskId = i;
Future future = executor.submit(() -> {
System.out.printf("任务 %d 在线程: %s%n", taskId, Thread.currentThread().getName());
try {
Thread.sleep(Duration.ofMillis(100 * (taskId + 1)));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "任务被中断";
}
return "任务 " + taskId + " 完成";
});
futures.add(future);
}
for (Future future : futures) {
System.out.println("结果: " + future.get());
}
}
}
private static void performanceComparison() {
System.out.println("\n--- 性能对比测试 ---");
int taskCount = 1000;
long virtualThreadTime = measureTime(() -> {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < taskCount; i++) {
executor.submit(() -> {
try {
Thread.sleep(Duration.ofMillis(1));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
}
});
System.out.printf("虚拟线程执行时间: %d ms%n", virtualThreadTime);
System.out.printf("性能提升显著!%n");
}
private static long measureTime(Runnable task) {
long start = System.currentTimeMillis();
task.run();
return System.currentTimeMillis() - start;
}
}
Java 21进一步增强了模式匹配功能,使得switch表达式更加强大和灵活。
public class PatternMatchingExample {
public static void main(String[] args) {
System.out.println("=== Java 21 模式匹配增强示例 ===");
basicPatternMatching();
recordPatternMatching();
guardedPatterns();
nestedPatterns();
}
private static void basicPatternMatching() {
System.out.println("\n--- 基本模式匹配 ---");
Object[] testObjects = {"Hello", 42, 3.14, null, new StringBuilder("Builder")};
for (Object obj : testObjects) {
String result = switch (obj) {
case String s -> "字符串: " + s + " (长度: " + s.length() + ")";
case Integer i -> "整数: " + i + " (" + (i > 0 ? "正数" : i < 0 ? "负数" : "零") + ")";
case Double d -> "浮点数: " + d;
case null -> "空值";
default -> "其他类型: " + obj.getClass().getSimpleName();
};
System.out.println(result);
}
}
private static void recordPatternMatching() {
System.out.println("\n--- 记录模式匹配 ---");
record Point(int x, int y) {}
record Circle(Point center, int radius) {}
record Rectangle(Point topLeft, Point bottomRight) {}
Object[] shapes = {
new Circle(new Point(0, 0), 5),
new Rectangle(new Point(1, 1), new Point(10, 10)),
new Point(3, 4)
};
for (Object shape : shapes) {
String description = switch (shape) {
case Circle(Point(var x, var y), var r) ->
String.format("圆: 圆心(%d,%d), 半径%d, 面积%.2f", x, y, r, Math.PI * r * r);
case Rectangle(Point(var x1, var y1), Point(var x2, var y2)) -> {
int width = Math.abs(x2 - x1);
int height = Math.abs(y2 - y1);
yield String.format("矩形: 从(%d,%d)到(%d,%d), 面积%d", x1, y1, x2, y2, width * height);
}
case Point(var x, var y) -> String.format("点: (%d,%d)", x, y);
default -> "未知形状";
};
System.out.println(description);
}
}
private static void guardedPatterns() {
System.out.println("\n--- 守卫模式 ---");
Object[] values = {"Java", "Python", "C++", 100, -50, 0};
for (Object value : values) {
String category = switch (value) {
case String s when s.length() > 4 -> "长编程语言名: " + s;
case String s -> "短编程语言名: " + s;
case Integer i when i > 50 -> "大整数: " + i;
case Integer i when i < 0 -> "负整数: " + i;
case Integer i -> "小非负整数: " + i;
default -> "其他类型";
};
System.out.println(category);
}
}
private static void nestedPatterns() {
System.out.println("\n--- 嵌套模式匹配 ---");
record Person(String name, int age) {}
record Employee(Person person, String department, double salary) {}
record Manager(Employee employee, int teamSize) {}
Object[] workers = {
new Employee(new Person("张三", 28), "开发部", 12000),
new Manager(new Employee(new Person("李四", 35), "技术部", 18000), 8),
new Person("王五", 22)
};
for (Object worker : workers) {
String info = switch (worker) {
case Manager(Employee(Person(var name, var age), var dept, var salary), var teamSize)
when salary > 15000 ->
String.format("高级经理 %s: %d岁, %s, 薪资%.0f, 管理%d人团队", name, age, dept, salary, teamSize);
case Manager(Employee(Person(var name, var age), var dept, var salary), var teamSize) ->
String.format("经理 %s: %d岁, %s, 薪资%.0f, 管理%d人团队", name, age, dept, salary, teamSize);
case Employee(Person(var name, var age), var dept, var salary) when age < 30 ->
String.format("年轻员工 %s: %d岁, %s, 薪资%.0f", name, age, dept, salary);
case Employee(Person(var name, var age), var dept, var salary) ->
String.format("资深员工 %s: %d岁, %s, 薪资%.0f", name, age, dept, salary);
case Person(var name, var age) ->
String.format("普通人员 %s: %d岁", name, age);
default -> "未知人员类型";
};
System.out.println(info);
}
}
}
字符串模板是Java 21引入的预览特性,提供了类型安全的字符串插值功能。
字符串模板是预览特性,需要使用 --enable-preview
标志来启用。在生产环境中使用前请谨慎考虑。
public class StringTemplateExample {
public static void main(String[] args) {
System.out.println("=== Java 21 字符串模板示例 ===");
basicStringTemplates();
expressionTemplates();
multiLineTemplates();
formattedTemplates();
customProcessor();
}
private static void basicStringTemplates() {
System.out.println("\n--- 基本字符串模板 ---");
String name = "Java";
int version = 21;
String feature = "字符串模板";
// 使用STR模板处理器
String message = STR."欢迎使用 \{name} \{version} 的新特性:\{feature}!";
System.out.println(message);
// 变量替换
String language = "Java";
String developer = "Oracle";
String info = STR."\{language} 是由 \{developer} 开发的编程语言";
System.out.println(info);
}
private static void expressionTemplates() {
System.out.println("\n--- 表达式模板 ---");
double price = 99.99;
int quantity = 3;
double discount = 0.1;
// 计算表达式
String invoice = STR."商品单价: \{price}元, 数量: \{quantity}个";
System.out.println(invoice);
String total = STR."小计: \{price * quantity}元";
System.out.println(total);
String finalPrice = STR."折扣后总价: \{(price * quantity) * (1 - discount)}元";
System.out.println(finalPrice);
// 方法调用
String timeInfo = STR."当前时间: \{java.time.LocalDateTime.now()}";
System.out.println(timeInfo);
}
private static void multiLineTemplates() {
System.out.println("\n--- 多行字符串模板 ---");
String productName = "Java 21 教程";
String author = "小傅哥";
double rating = 4.8;
int reviews = 1250;
String report = STR."""
╔══════════════════════════════════════╗
║ 产品信息报告 ║
╠══════════════════════════════════════╣
║ 产品名称: \{productName} ║
║ 作者: \{author} ║
║ 评分: \{rating}/5.0 ║
║ 评论数: \{reviews} ║
║ 推荐指数: \{rating > 4.5 ? "⭐⭐⭐⭐⭐" : "⭐⭐⭐⭐"} ║
╚══════════════════════════════════════╝
""";
System.out.println(report);
}
private static void formattedTemplates() {
System.out.println("\n--- 格式化模板 ---");
double pi = Math.PI;
int number = 42;
String text = "Hello";
// 使用FMT进行格式化
String formatted1 = FMT."π的值: %.4f\{pi}";
System.out.println(formatted1);
String formatted2 = FMT."数字: %08d\{number}";
System.out.println(formatted2);
String formatted3 = FMT."文本: %10s\{text}";
System.out.println(formatted3);
// 组合格式化
String combined = FMT."结果: %s\{text} - %d\{number} - %.2f\{pi}";
System.out.println(combined);
}
private static void customProcessor() {
System.out.println("\n--- 自定义模板处理器 ---");
String greeting = "hello";
String target = "world";
String message = "java";
// 使用自定义的大写处理器
String upperResult = UPPER."\{greeting} \{target}! Welcome to \{message}";
System.out.println("大写处理器结果: " + upperResult);
// 使用自定义的JSON处理器
String name = "张三";
int age = 25;
String city = "北京";
String jsonResult = JSON."\{name}, \{age}, \{city}";
System.out.println("JSON处理器结果: " + jsonResult);
}
// 自定义大写模板处理器
public static final StringTemplate.Processor UPPER =
StringTemplate.Processor.of((StringTemplate st) -> {
StringBuilder sb = new StringBuilder();
Iterator fragments = st.fragments().iterator();
Iterator
Java 21引入了序列化集合接口,为有序集合提供了统一的API,包括首尾元素的操作方法。
import java.util.*;
public class SequencedCollectionsExample {
public static void main(String[] args) {
System.out.println("=== Java 21 序列化集合示例 ===");
demonstrateSequencedList();
demonstrateSequencedSet();
demonstrateSequencedMap();
practicalExamples();
}
private static void demonstrateSequencedList() {
System.out.println("\n--- SequencedList 示例 ---");
List list = new ArrayList<>();
// 添加元素到首尾
list.addFirst("开始");
list.addLast("结束");
list.add(1, "中间");
System.out.println("列表内容: " + list);
// 获取首尾元素
System.out.println("第一个元素: " + list.getFirst());
System.out.println("最后一个元素: " + list.getLast());
// 反向视图
List reversed = list.reversed();
System.out.println("反向视图: " + reversed);
// 移除首尾元素
String removedFirst = list.removeFirst();
String removedLast = list.removeLast();
System.out.println("移除的第一个: " + removedFirst);
System.out.println("移除的最后一个: " + removedLast);
System.out.println("剩余内容: " + list);
}
private static void demonstrateSequencedSet() {
System.out.println("\n--- SequencedSet 示例 ---");
SequencedSet set = new LinkedHashSet<>();
// 添加元素
set.addFirst(1);
set.addLast(3);
set.add(2);
set.addFirst(0);
System.out.println("集合内容: " + set);
// 获取首尾元素
System.out.println("第一个元素: " + set.getFirst());
System.out.println("最后一个元素: " + set.getLast());
// 反向视图
SequencedSet reversedSet = set.reversed();
System.out.println("反向集合: " + reversedSet);
// 移除首尾元素
Integer removedFirst = set.removeFirst();
Integer removedLast = set.removeLast();
System.out.println("移除的第一个: " + removedFirst);
System.out.println("移除的最后一个: " + removedLast);
System.out.println("剩余集合: " + set);
}
private static void demonstrateSequencedMap() {
System.out.println("\n--- SequencedMap 示例 ---");
SequencedMap map = new LinkedHashMap<>();
// 添加键值对
map.put("second", "第二个");
map.put("third", "第三个");
map.putFirst("first", "第一个");
map.putLast("fourth", "第四个");
System.out.println("映射内容: " + map);
// 获取首尾条目
System.out.println("第一个条目: " + map.firstEntry());
System.out.println("最后一个条目: " + map.lastEntry());
// 反向视图
SequencedMap reversedMap = map.reversed();
System.out.println("反向映射: " + reversedMap);
// 序列化键和值的视图
System.out.println("序列化键: " + map.sequencedKeySet());
System.out.println("序列化值: " + map.sequencedValues());
System.out.println("序列化条目: " + map.sequencedEntrySet());
}
private static void practicalExamples() {
System.out.println("\n--- 实际应用示例 ---");
// 示例1: 最近访问的页面
recentPagesExample();
// 示例2: 任务队列
taskQueueExample();
// 示例3: 缓存实现
cacheExample();
}
private static void recentPagesExample() {
System.out.println("\n最近访问页面管理:");
List recentPages = new ArrayList<>();
int maxPages = 5;
String[] visitedPages = {"首页", "产品页", "关于我们", "联系我们", "帮助页面", "用户中心"};
for (String page : visitedPages) {
// 如果页面已存在,先移除
recentPages.remove(page);
// 添加到最前面
recentPages.addFirst(page);
// 保持最大数量
if (recentPages.size() > maxPages) {
recentPages.removeLast();
}
System.out.println("访问 " + page + " 后的最近页面: " + recentPages);
}
}
private static void taskQueueExample() {
System.out.println("\n任务队列管理:");
List taskQueue = new ArrayList<>();
// 添加普通任务到队尾
taskQueue.addLast("普通任务1");
taskQueue.addLast("普通任务2");
// 添加紧急任务到队首
taskQueue.addFirst("紧急任务1");
taskQueue.addFirst("紧急任务2");
System.out.println("任务队列: " + taskQueue);
// 处理任务(从队首开始)
while (!taskQueue.isEmpty()) {
String task = taskQueue.removeFirst();
System.out.println("正在处理: " + task + ", 剩余任务: " + taskQueue);
}
}
private static void cacheExample() {
System.out.println("\nLRU缓存实现:");
SequencedMap cache = new LinkedHashMap<>();
int maxSize = 3;
String[] operations = {"get:A", "put:A:值A", "put:B:值B", "get:A", "put:C:值C", "put:D:值D"};
for (String op : operations) {
String[] parts = op.split(":");
String operation = parts[0];
String key = parts[1];
if ("get".equals(operation)) {
String value = cache.get(key);
if (value != null) {
// 移动到最后(最近使用)
cache.remove(key);
cache.putLast(key, value);
System.out.println("获取 " + key + ": " + value);
} else {
System.out.println("获取 " + key + ": 未找到");
}
} else if ("put".equals(operation)) {
String value = parts[2];
// 如果已存在,先移除
cache.remove(key);
// 添加到最后
cache.putLast(key, value);
// 检查大小限制
if (cache.size() > maxSize) {
Map.Entry oldest = cache.pollFirstEntry();
System.out.println("缓存已满,移除最旧的: " + oldest.getKey());
}
System.out.println("存储 " + key + ": " + value);
}
System.out.println("当前缓存: " + cache);
}
}
}
// 1. 改进的switch表达式
public class OtherFeaturesExample {
// Key Encapsulation Mechanism API
public static void demonstrateKEM() {
try {
// 生成密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("X25519");
KeyPair keyPair = kpg.generateKeyPair();
// 使用KEM API
KEM kem = KEM.getInstance("DHKEM");
KEM.Encapsulator encapsulator = kem.newEncapsulator(keyPair.getPublic());
KEM.Encapsulated encapsulated = encapsulator.encapsulate();
System.out.println("密钥封装完成");
} catch (Exception e) {
e.printStackTrace();
}
}
// 改进的Math类方法
public static void demonstrateMathImprovements() {
// 新的数学方法
long result1 = Math.clamp(15, 10, 20); // 结果: 15
long result2 = Math.clamp(5, 10, 20); // 结果: 10
long result3 = Math.clamp(25, 10, 20); // 结果: 20
System.out.println("Clamp结果: " + result1 + ", " + result2 + ", " + result3);
}
// 改进的StringBuilder和StringBuffer
public static void demonstrateStringBuilderImprovements() {
StringBuilder sb = new StringBuilder();
// 新的repeat方法
sb.repeat("Hello ", 3);
System.out.println(sb.toString()); // "Hello Hello Hello "
// 改进的性能
sb.setLength(0);
for (int i = 0; i < 1000; i++) {
sb.append("item").append(i).append(" ");
}
System.out.println("StringBuilder性能测试完成");
}
}
Java 21作为LTS版本,提供了良好的向后兼容性。大多数Java 8、11、17应用程序可以直接在Java 21上运行。
// 1. 检查依赖兼容性
// 确保所有第三方库支持Java 21
// 2. 更新构建配置
// Maven pom.xml
21
21
// Gradle build.gradle
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
// 3. 启用预览特性(如果需要)
// javac --enable-preview --release 21 *.java
// java --enable-preview MyClass
// 4. 性能测试
// 在生产环境部署前进行充分的性能测试
// 5. 逐步采用新特性
// 优先使用虚拟线程改进并发性能
// 使用序列化集合简化代码
// 考虑使用模式匹配提高代码可读性