JDK 21 API增强详解
1. Sequenced Collections(序列化集合)
特性概述
Sequenced Collections为Java集合框架添加了统一的顺序访问API。这个特性解决了不同集合类型(List、Set、Map)在顺序操作上API不一致的问题,提供了更统一和直观的接口。
技术细节
Sequenced Collections引入的核心接口和方法:
SequencedCollection<E>:顺序集合的根接口SequencedSet<E>:顺序Set接口SequencedMap<K,V>:顺序Map接口- 统一的顺序操作方法:
getFirst(),getLast(),reversed()等
代码示例
java
// Sequenced Collections基本使用
import java.util.*;
public class SequencedCollectionsExample {
public static void main(String[] args) {
// List作为SequencedCollection使用
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C", "D"));
demonstrateSequencedCollection(list);
// LinkedHashSet作为SequencedSet使用
Set<String> set = new LinkedHashSet<>(Arrays.asList("X", "Y", "Z"));
demonstrateSequencedSet(set);
// LinkedHashMap作为SequencedMap使用
Map<String, Integer> map = new LinkedHashMap<>();
map.put("first", 1);
map.put("second", 2);
map.put("third", 3);
demonstrateSequencedMap(map);
}
public static void demonstrateSequencedCollection(SequencedCollection<String> collection) {
System.out.println("=== Sequenced Collection Demo ===");
System.out.println("Original: " + collection);
System.out.println("First element: " + collection.getFirst());
System.out.println("Last element: " + collection.getLast());
// 反转视图
SequencedCollection<String> reversed = collection.reversed();
System.out.println("Reversed: " + reversed);
System.out.println("First in reversed: " + reversed.getFirst());
System.out.println("Last in reversed: " + reversed.getLast());
// 添加元素到开头和结尾
collection.addFirst("START");
collection.addLast("END");
System.out.println("After adding: " + collection);
System.out.println();
}
public static void demonstrateSequencedSet(SequencedSet<String> set) {
System.out.println("=== Sequenced Set Demo ===");
System.out.println("Original: " + set);
System.out.println("First element: " + set.getFirst());
System.out.println("Last element: " + set.getLast());
// 反转视图
SequencedSet<String> reversed = set.reversed();
System.out.println("Reversed: " + reversed);
// 添加元素
set.addFirst("BEGIN");
set.addLast("FINISH");
System.out.println("After adding: " + set);
System.out.println();
}
public static void demonstrateSequencedMap(SequencedMap<String, Integer> map) {
System.out.println("=== Sequenced Map Demo ===");
System.out.println("Original: " + map);
System.out.println("First entry: " + map.firstEntry());
System.out.println("Last entry: " + map.lastEntry());
// 反转视图
SequencedMap<String, Integer> reversed = map.reversed();
System.out.println("Reversed: " + reversed);
System.out.println("First entry in reversed: " + reversed.firstEntry());
// 添加条目到开头和结尾
map.putFirst("zero", 0);
map.putLast("four", 4);
System.out.println("After adding: " + map);
System.out.println();
}
}
// 实际应用场景
public class SequencedCollectionsUseCases {
// 统一处理不同类型的顺序集合
public static <E> void processSequencedCollection(SequencedCollection<E> collection) {
if (collection.isEmpty()) {
System.out.println("Collection is empty");
return;
}
System.out.println("Processing collection: " + collection);
System.out.println("First element: " + collection.getFirst());
System.out.println("Last element: " + collection.getLast());
System.out.println("Size: " + collection.size());
// 反向处理
System.out.println("Reverse processing:");
collection.reversed().forEach(System.out::println);
}
// 队列操作的简化
public static <E> void demonstrateQueueOperations(SequencedCollection<E> collection) {
// 添加到队尾
collection.addLast((E) "New Item");
System.out.println("After enqueue: " + collection);
// 从队头移除
E first = collection.removeFirst();
System.out.println("Dequeued: " + first);
System.out.println("After dequeue: " + collection);
}
// 栈操作的简化
public static <E> void demonstrateStackOperations(SequencedCollection<E> collection) {
// 压栈
collection.addFirst((E) "Stack Item");
System.out.println("After push: " + collection);
// 弹栈
E last = collection.removeFirst();
System.out.println("Popped: " + last);
System.out.println("After pop: " + collection);
}
// Map的顺序操作
public static <K, V> void demonstrateMapSequencing(SequencedMap<K, V> map) {
System.out.println("Map entries in order:");
map.sequencedEntrySet().forEach(entry ->
System.out.println(entry.getKey() + " -> " + entry.getValue()));
System.out.println("Keys in order:");
map.sequencedKeySet().forEach(System.out::println);
System.out.println("Values in order:");
map.sequencedValues().forEach(System.out::println);
}
}
// 自定义Sequenced Collection实现
public class CustomSequencedCollection<E>
implements SequencedCollection<E> {
private final Deque<E> deque = new ArrayDeque<>();
@Override
public int size() {
return deque.size();
}
@Override
public boolean isEmpty() {
return deque.isEmpty();
}
@Override
public boolean contains(Object o) {
return deque.contains(o);
}
@Override
public Iterator<E> iterator() {
return deque.iterator();
}
@Override
public Object[] toArray() {
return deque.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return deque.toArray(a);
}
@Override
public boolean add(E e) {
return deque.add(e);
}
@Override
public boolean remove(Object o) {
return deque.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return deque.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return deque.addAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return deque.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return deque.retainAll(c);
}
@Override
public void clear() {
deque.clear();
}
// SequencedCollection特有的方法
@Override
public E getFirst() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return deque.getFirst();
}
@Override
public E getLast() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return deque.getLast();
}
@Override
public void addFirst(E e) {
deque.addFirst(e);
}
@Override
public void addLast(E e) {
deque.addLast(e);
}
@Override
public E removeFirst() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return deque.removeFirst();
}
@Override
public E removeLast() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return deque.removeLast();
}
@Override
public SequencedCollection<E> reversed() {
return new ReversedSequencedCollection<>(this);
}
// Reversed view implementation
private static class ReversedSequencedCollection<E>
implements SequencedCollection<E> {
private final SequencedCollection<E> original;
ReversedSequencedCollection(SequencedCollection<E> original) {
this.original = original;
}
@Override
public int size() {
return original.size();
}
@Override
public boolean isEmpty() {
return original.isEmpty();
}
@Override
public boolean contains(Object o) {
return original.contains(o);
}
@Override
public Iterator<E> iterator() {
return original.reversed().iterator();
}
@Override
public Object[] toArray() {
Object[] array = original.toArray();
Collections.reverse(Arrays.asList(array));
return array;
}
@Override
public <T> T[] toArray(T[] a) {
T[] array = original.toArray(a);
Collections.reverse(Arrays.asList(array));
return array;
}
@Override
public boolean add(E e) {
return original.add(e);
}
@Override
public boolean remove(Object o) {
return original.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return original.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return original.addAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return original.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return original.retainAll(c);
}
@Override
public void clear() {
original.clear();
}
@Override
public E getFirst() {
return original.getLast();
}
@Override
public E getLast() {
return original.getFirst();
}
@Override
public void addFirst(E e) {
original.addLast(e);
}
@Override
public void addLast(E e) {
original.addFirst(e);
}
@Override
public E removeFirst() {
return original.removeLast();
}
@Override
public E removeLast() {
return original.removeFirst();
}
@Override
public SequencedCollection<E> reversed() {
return original;
}
}
}
使用建议
-
适用场景:
- 需要统一处理不同顺序集合的场景
- 简化队列和栈操作
- 需要反向遍历集合的场景
-
最佳实践:
- 优先使用SequencedCollection接口而非具体实现类
- 合理利用reversed()方法进行反向操作
- 在API设计中考虑使用Sequenced Collection接口
-
注意事项:
- 注意不同集合类型对顺序的保证程度
- HashSet等无序集合不实现SequencedSet接口
- 合理处理空集合的异常情况
2. String Templates(字符串模板,预览特性)
特性概述
String Templates是JDK 21中的预览特性,提供了字符串插值的新方式。它比传统的字符串拼接更安全、更高效,并且支持模板表达式的验证。
技术细节
String Templates的核心组件:
TemplateProcessor:处理模板的接口STR:内置的字符串模板处理器FMT:格式化字符串模板处理器- 模板表达式语法:使用
\{expression}形式
代码示例
java
// 需要添加JVM参数:--enable-preview --source 21
// String Templates基本使用
public class StringTemplatesExample {
public static void main(String[] args) {
// 基本字符串模板
String name = "Alice";
int age = 30;
String message = STR."Hello, \{name}! You are \{age} years old.";
System.out.println(message);
// 复杂表达式
List<String> items = Arrays.asList("Apple", "Banana", "Orange");
String listMessage = STR."Items: \{String.join(", ", items)}";
System.out.println(listMessage);
// 嵌套模板
String greeting = STR."Welcome, \{name}!";
String fullMessage = STR."\{greeting} Today is \{LocalDate.now()}";
System.out.println(fullMessage);
// 使用FMT进行格式化
double price = 123.456;
String formatted = FMT."Price: $\{price%.2f}";
System.out.println(formatted);
// 多行模板
String multiLine = STR."""
User Information:
Name: \{name}
Age: \{age}
Items: \{String.join(", ", items)}
""";
System.out.println(multiLine);
}
// 实际应用场景
public static void demonstrateUseCases() {
// SQL查询模板
String tableName = "users";
String condition = "age > 18";
String sql = STR."SELECT * FROM \{tableName} WHERE \{condition}";
System.out.println("SQL: " + sql);
// JSON生成模板
String username = "john_doe";
String email = "john@example.com";
String json = STR."""
{
"username": "\{username}",
"email": "\{email}",
"created": "\{LocalDateTime.now()}"
}
""";
System.out.println("JSON: " + json);
// 日志消息模板
String methodName = "processData";
int recordCount = 1000;
String logMessage = STR."[\{LocalTime.now()}] \{methodName}: Processed \{recordCount} records";
System.out.println("Log: " + logMessage);
}
// 自定义模板处理器
public static void customTemplateProcessor() {
// 创建自定义模板处理器
TemplateProcessor<String> upperCaseProcessor = TemplateProcessor.of(
(template, values) -> {
String result = template.interpolate(values);
return result.toUpperCase();
}
);
String name = "alice";
String greeting = upperCaseProcessor."Hello, \{name}!";
System.out.println(greeting); // 输出: HELLO, ALICE!
}
// 安全性示例
public static void securityExample() {
// 传统的字符串拼接可能存在的安全问题
String userInput = "'; DROP TABLE users; --";
// 不安全的方式(示例)
// String unsafeQuery = "SELECT * FROM users WHERE name = '" + userInput + "'";
// 使用模板的安全方式
String safeQuery = STR."SELECT * FROM users WHERE name = '\{userInput}'";
System.out.println("Safe query: " + safeQuery);
// 模板会自动处理特殊字符的转义
}
}
使用建议
-
适用场景:
- 需要字符串插值的场景
- 生成SQL查询、JSON、XML等结构化文本
- 日志消息格式化
-
最佳实践:
- 优先使用STR和FMT内置处理器
- 在多行文本中使用字符串模板
- 注意模板表达式的复杂度
-
注意事项:
- 这是预览特性,API可能发生变化
- 需要启用预览特性才能使用
- 注意模板表达式的性能影响
3. Scoped Values(作用域值,预览特性)
特性概述
Scoped Values是JDK 21中的预览特性,提供了在线程内和线程间共享不可变数据的新方式。它是ThreadLocal的现代化替代方案,特别适合与虚拟线程一起使用。
技术细节
Scoped Values的核心特性:
- 不可变性:一旦设置就不能修改
- 作用域绑定:在特定代码块内绑定值
- 线程继承:子线程可以访问父线程的作用域值
- 与虚拟线程兼容:比ThreadLocal更适合虚拟线程
代码示例
java
// 需要添加JVM参数:--enable-preview --source 21
import jdk.incubator.concurrent.ScopedValue;
public class ScopedValuesExample {
// 定义作用域值
private static final ScopedValue<String> USER_ID = ScopedValue.newInstance();
private static final ScopedValue<String> REQUEST_ID = ScopedValue.newInstance();
private static final ScopedValue<Boolean> DEBUG_MODE = ScopedValue.newInstance();
public static void main(String[] args) {
// 基本使用
ScopedValue.where(USER_ID, "user123")
.where(REQUEST_ID, "req456")
.where(DEBUG_MODE, true)
.run(() -> {
processRequest();
});
}
public static void processRequest() {
// 在作用域内访问值
System.out.println("User ID: " + USER_ID.get());
System.out.println("Request ID: " + REQUEST_ID.get());
System.out.println("Debug mode: " + DEBUG_MODE.get());
// 调用其他方法
performDatabaseOperation();
callExternalService();
}
public static void performDatabaseOperation() {
// 在同一线程中访问作用域值
String userId = USER_ID.get();
String requestId = REQUEST_ID.get();
System.out.println("DB Operation - User: " + userId + ", Request: " + requestId);
// 创建子线程(虚拟线程)
Thread.ofVirtual().start(() -> {
// 子线程可以访问父线程的作用域值
System.out.println("Virtual Thread - User: " + USER_ID.get() +
", Request: " + REQUEST_ID.get());
});
}
public static void callExternalService() {
// 嵌套作用域
ScopedValue.where(DEBUG_MODE, false)
.run(() -> {
System.out.println("External Service - Debug: " + DEBUG_MODE.get());
// 调用外部服务
});
}
// 实际应用场景
public static void webFrameworkExample() {
// 模拟Web框架中的请求处理
String userId = "user789";
String requestId = java.util.UUID.randomUUID().toString();
boolean isDebug = true;
ScopedValue.where(USER_ID, userId)
.where(REQUEST_ID, requestId)
.where(DEBUG_MODE, isDebug)
.run(() -> {
handleHttpRequest();
});
}
public static void handleHttpRequest() {
// 记录请求信息
logInfo("Handling request for user: " + USER_ID.get());
// 业务逻辑处理
processData();
// 响应处理
sendResponse();
}
public static void processData() {
if (DEBUG_MODE.get()) {
logDebug("Processing data for request: " + REQUEST_ID.get());
}
// 模拟数据处理
// 创建多个虚拟线程处理并发任务
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int taskId = i;
Thread vt = Thread.ofVirtual().start(() -> {
// 虚拟线程可以访问作用域值
logInfo("Task " + taskId + " processing for user: " + USER_ID.get());
});
threads.add(vt);
}
// 等待所有任务完成
threads.forEach(thread -> {
try {
thread.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
}
public static void sendResponse() {
logInfo("Sending response for request: " + REQUEST_ID.get());
}
// 日志方法使用作用域值
public static void logInfo(String message) {
System.out.println("[INFO] [" + REQUEST_ID.get() + "] " + message);
}
public static void logDebug(String message) {
if (DEBUG_MODE.get()) {
System.out.println("[DEBUG] [" + REQUEST_ID.get() + "] " + message);
}
}
// 与传统ThreadLocal的对比
public static void compareWithThreadLocal() {
// ThreadLocal方式
ThreadLocal<String> userIdTL = new ThreadLocal<>();
userIdTL.set("user123");
System.out.println("ThreadLocal value: " + userIdTL.get());
userIdTL.remove();
// Scoped Value方式
ScopedValue<String> userIdSV = ScopedValue.newInstance();
ScopedValue.where(userIdSV, "user123")
.run(() -> {
System.out.println("Scoped Value: " + userIdSV.get());
});
// 作用域结束后自动清理
}
}
使用建议
-
适用场景:
- 跨方法传递上下文信息
- Web应用中的请求上下文
- 与虚拟线程一起使用的场景
-
最佳实践:
- 优先使用Scoped Values替代ThreadLocal
- 在需要跨线程共享数据时使用
- 合理设计作用域的边界
-
注意事项:
- 这是预览特性,API可能发生变化
- 需要启用预览特性才能使用
- 作用域值是不可变的,不能修改
4. Key Encapsulation Mechanism API(密钥封装机制API)
特性概述
Key Encapsulation Mechanism API为后量子密码学提供了支持,允许使用后量子加密算法进行密钥封装和解封装操作。
技术细节
KEM API的核心组件:
KeyEncapsulationMechanism:密钥封装机制接口KEM:KEM工厂类SecretKey:封装的密钥- 支持多种后量子加密算法
代码示例
java
// Key Encapsulation Mechanism API示例
import javax.crypto.KEM;
import javax.crypto.SecretKey;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
public class KEMExample {
public static void main(String[] args) {
try {
// 创建密钥对
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
kpg.initialize(256);
KeyPair keyPair = kpg.generateKeyPair();
// 注意:JDK 21中的KEM API主要用于后量子加密
// 这里展示API的使用方式,实际使用需要相应的后量子算法支持
System.out.println("KEM API演示框架");
System.out.println("密钥对已生成");
} catch (Exception e) {
e.printStackTrace();
}
}
// KEM使用示例(概念性)
public static void demonstrateKEMUsage() {
/*
// 获取KEM实例(需要后量子算法支持)
KEM kem = KEM.getInstance("CRYSTALS-Kyber");
// 生成密钥对
KEM.KeyPairGenerator kpg = kem.newKeyPairGenerator();
KEM.KeyPair keyPair = kpg.generateKeyPair();
// 发送方:封装密钥
KEM.Encapsulator encapsulator = kem.newEncapsulator(keyPair.getPublic());
KEM.Encapsulated encap = encapsulator.encapsulate();
// 接收方:解封装密钥
KEM.Decapsulator decapsulator = kem.newDecapsulator(keyPair.getPrivate());
SecretKey sharedSecret = decapsulator.decapsulate(encap.encapsulation());
System.out.println("密钥封装完成");
*/
}
}
总结
JDK 21的API增强主要集中在以下几个方面:
- Sequenced Collections:提供了统一的顺序集合API,简化了集合操作
- String Templates:提供了更安全、更高效的字符串插值方式
- Scoped Values:提供了现代化的线程本地变量替代方案
- KEM API:为后量子加密提供了支持
这些API增强不仅提高了Java平台的功能性,还增强了开发者的编程体验,为构建更安全、更高效的应用程序提供了更好的工具支持。