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()

代码示例

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;
        }
    }
}

使用建议

  1. 适用场景

    • 需要统一处理不同顺序集合的场景
    • 简化队列和栈操作
    • 需要反向遍历集合的场景
  2. 最佳实践

    • 优先使用SequencedCollection接口而非具体实现类
    • 合理利用reversed()方法进行反向操作
    • 在API设计中考虑使用Sequenced Collection接口
  3. 注意事项

    • 注意不同集合类型对顺序的保证程度
    • 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);
        // 模板会自动处理特殊字符的转义
    }
}

使用建议

  1. 适用场景

    • 需要字符串插值的场景
    • 生成SQL查询、JSON、XML等结构化文本
    • 日志消息格式化
  2. 最佳实践

    • 优先使用STR和FMT内置处理器
    • 在多行文本中使用字符串模板
    • 注意模板表达式的复杂度
  3. 注意事项

    • 这是预览特性,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());
                  });
        // 作用域结束后自动清理
    }
}

使用建议

  1. 适用场景

    • 跨方法传递上下文信息
    • Web应用中的请求上下文
    • 与虚拟线程一起使用的场景
  2. 最佳实践

    • 优先使用Scoped Values替代ThreadLocal
    • 在需要跨线程共享数据时使用
    • 合理设计作用域的边界
  3. 注意事项

    • 这是预览特性,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增强主要集中在以下几个方面:

  1. Sequenced Collections:提供了统一的顺序集合API,简化了集合操作
  2. String Templates:提供了更安全、更高效的字符串插值方式
  3. Scoped Values:提供了现代化的线程本地变量替代方案
  4. KEM API:为后量子加密提供了支持

这些API增强不仅提高了Java平台的功能性,还增强了开发者的编程体验,为构建更安全、更高效的应用程序提供了更好的工具支持。

相关推荐
β添砖java3 小时前
JS基础Day01
开发语言·javascript·ecmascript
学习编程的Kitty3 小时前
JavaEE初阶——多线程(3)线程安全
java·开发语言·jvm
Skrrapper3 小时前
【C++】C++ 中的 map
开发语言·c++
m0_748233644 小时前
【C++list】底层结构、迭代器核心原理与常用接口实现全解析
c++·windows·list
寄思~4 小时前
python批量读取word表格写入excel固定位置
开发语言·python·excel
workflower5 小时前
微软PM的来历
java·开发语言·算法·microsoft·django·结对编程
惊讶的猫5 小时前
c++基础
开发语言·c++
江湖一码农5 小时前
[小白]spring boot接入emqx
java·数据库·spring boot
人间乄惊鸿客6 小时前
python — day9
开发语言·python