JDK 21 API增强详解
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()
等
代码示例
// 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<>();@Overridepublic int size() {return deque.size();}@Overridepublic boolean isEmpty() {return deque.isEmpty();}@Overridepublic boolean contains(Object o) {return deque.contains(o);}@Overridepublic Iterator<E> iterator() {return deque.iterator();}@Overridepublic Object[] toArray() {return deque.toArray();}@Overridepublic <T> T[] toArray(T[] a) {return deque.toArray(a);}@Overridepublic boolean add(E e) {return deque.add(e);}@Overridepublic boolean remove(Object o) {return deque.remove(o);}@Overridepublic boolean containsAll(Collection<?> c) {return deque.containsAll(c);}@Overridepublic boolean addAll(Collection<? extends E> c) {return deque.addAll(c);}@Overridepublic boolean removeAll(Collection<?> c) {return deque.removeAll(c);}@Overridepublic boolean retainAll(Collection<?> c) {return deque.retainAll(c);}@Overridepublic void clear() {deque.clear();}// SequencedCollection特有的方法@Overridepublic E getFirst() {if (isEmpty()) {throw new NoSuchElementException();}return deque.getFirst();}@Overridepublic E getLast() {if (isEmpty()) {throw new NoSuchElementException();}return deque.getLast();}@Overridepublic void addFirst(E e) {deque.addFirst(e);}@Overridepublic void addLast(E e) {deque.addLast(e);}@Overridepublic E removeFirst() {if (isEmpty()) {throw new NoSuchElementException();}return deque.removeFirst();}@Overridepublic E removeLast() {if (isEmpty()) {throw new NoSuchElementException();}return deque.removeLast();}@Overridepublic SequencedCollection<E> reversed() {return new ReversedSequencedCollection<>(this);}// Reversed view implementationprivate static class ReversedSequencedCollection<E> implements SequencedCollection<E> {private final SequencedCollection<E> original;ReversedSequencedCollection(SequencedCollection<E> original) {this.original = original;}@Overridepublic int size() {return original.size();}@Overridepublic boolean isEmpty() {return original.isEmpty();}@Overridepublic boolean contains(Object o) {return original.contains(o);}@Overridepublic Iterator<E> iterator() {return original.reversed().iterator();}@Overridepublic Object[] toArray() {Object[] array = original.toArray();Collections.reverse(Arrays.asList(array));return array;}@Overridepublic <T> T[] toArray(T[] a) {T[] array = original.toArray(a);Collections.reverse(Arrays.asList(array));return array;}@Overridepublic boolean add(E e) {return original.add(e);}@Overridepublic boolean remove(Object o) {return original.remove(o);}@Overridepublic boolean containsAll(Collection<?> c) {return original.containsAll(c);}@Overridepublic boolean addAll(Collection<? extends E> c) {return original.addAll(c);}@Overridepublic boolean removeAll(Collection<?> c) {return original.removeAll(c);}@Overridepublic boolean retainAll(Collection<?> c) {return original.retainAll(c);}@Overridepublic void clear() {original.clear();}@Overridepublic E getFirst() {return original.getLast();}@Overridepublic E getLast() {return original.getFirst();}@Overridepublic void addFirst(E e) {original.addLast(e);}@Overridepublic void addLast(E e) {original.addFirst(e);}@Overridepublic E removeFirst() {return original.removeLast();}@Overridepublic E removeLast() {return original.removeFirst();}@Overridepublic 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}
形式
代码示例
// 需要添加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更适合虚拟线程
代码示例
// 需要添加JVM参数:--enable-preview --source 21import 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
:封装的密钥- 支持多种后量子加密算法
代码示例
// 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平台的功能性,还增强了开发者的编程体验,为构建更安全、更高效的应用程序提供了更好的工具支持。