目录

Java 核心特性详解:从基础到进阶

从 OOP 到虚拟线程,深入理解 Java 核心技术栈与设计哲学

Java 作为一门历经二十余年依然活跃的编程语言,其设计理念和技术特性值得每一位开发者深入理解。本文将从核心特性出发,详细解析 Java 的技术优势与实现原理。

一、面向对象编程(OOP)

1.1 四大基本特性

Java 是完全面向对象的语言,支持以下核心概念:

封装(Encapsulation)

将数据(属性)和操作数据的方法绑定在一起,隐藏内部实现细节。

public class BankAccount {
    private double balance;  // 私有属性,外部无法直接访问
    
    // 通过公共方法控制访问
    public void deposit(double amount) {
        if (amount > 0) {
            this.balance += amount;
        }
    }
    
    public double getBalance() {
        return this.balance;
    }
}

继承(Inheritance)

子类继承父类的属性和方法,实现代码复用和扩展。

// 父类
public class Animal {
    protected String name;
    
    public void eat() {
        System.out.println(name + " is eating");
    }
}

// 子类
public class Dog extends Animal {
    public void bark() {
        System.out.println(name + " is barking");
    }
}

多态(Polymorphism)

同一操作作用于不同对象产生不同行为,分为编译时多态(重载)和运行时多态(重写)。

// 运行时多态
Animal animal = new Dog();  // 父类引用指向子类对象
animal.eat();  // 调用的是 Dog 类的 eat 方法(如果被重写)

// 编译时多态(方法重载)
public class Calculator {
    public int add(int a, int b) { return a + b; }
    public double add(double a, double b) { return a + b; }
    public int add(int a, int b, int c) { return a + b + c; }
}

抽象(Abstraction)

提取共性,隐藏复杂性,通过抽象类和接口实现。

// 抽象类
public abstract class Shape {
    protected String color;
    
    // 抽象方法,子类必须实现
    public abstract double calculateArea();
    
    // 具体方法
    public void setColor(String color) {
        this.color = color;
    }
}

// 接口
public interface Drawable {
    void draw();  // 隐式 public abstract
    default void printInfo() {  // 默认方法
        System.out.println("This is drawable");
    }
}

1.2 类与对象的关系

概念说明示例
类(Class)对象的模板,定义属性和行为class Car { }
对象(Object)类的实例Car myCar = new Car();
构造方法创建对象时初始化public Car() { }
this指向当前对象引用this.name = name;
super指向父类引用super.method();

二、跨平台性(Write Once, Run Anywhere)

2.1 实现原理

Java 的跨平台性依赖于 JVM(Java Virtual Machine)

Java 源代码 (.java)
    ↓ 编译
字节码 (.class)
    ↓ JVM 解释/编译执行
Windows / Linux / macOS

2.2 JVM 架构

┌─────────────────────────────────────────┐
│              Java 程序                   │
├─────────────────────────────────────────┤
│  类加载器子系统 (Class Loader Subsystem)  │
├─────────────────────────────────────────┤
│  运行时数据区 (Runtime Data Areas)       │
│  ├─ 堆 (Heap)                           │
│  ├─ 虚拟机栈 (VM Stack)                 │
│  ├─ 本地方法栈 (Native Method Stack)    │
│  ├─ 程序计数器 (PC Register)            │
│  └─ 方法区 (Method Area)                │
├─────────────────────────────────────────┤
│  执行引擎 (Execution Engine)             │
│  ├─ 解释器 (Interpreter)                │
│  └─ JIT 编译器 (Just-In-Time Compiler)  │
└─────────────────────────────────────────┘

2.3 字节码示例

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

编译后使用 javap -c Hello 查看字节码:

Code:
   0: getstatic     #2    // Field java/lang/System.out:Ljava/io/PrintStream;
   3: ldc           #3    // String Hello, World!
   5: invokevirtual #4    // Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8: return

三、自动内存管理(垃圾回收)

3.1 内存区域划分

┌─────────────────────────────────────┐
│            堆内存 (Heap)             │
│  ┌──────────────┬────────────────┐  │
│  │   年轻代      │     老年代      │  │
│  │  (Young Gen) │  (Old Gen)     │  │
│  │  ├─ Eden     │                │  │
│  │  ├─ S0       │                │  │
│  │  └─ S1       │                │  │
│  └──────────────┴────────────────┘  │
├─────────────────────────────────────┤
│         元空间 (Metaspace)           │
│     (替代永久代 PermGen)            │
└─────────────────────────────────────┘

3.2 垃圾回收算法

算法原理优点缺点
标记-清除标记存活对象,清除未标记简单产生碎片
复制将存活对象复制到另一块内存无碎片内存减半
标记-整理标记后移动存活对象到一端无碎片移动成本高
分代收集年轻代用复制,老年代用标记-整理高效复杂

3.3 垃圾收集器对比

// JVM 参数设置收集器
// G1 收集器(JDK 9+ 默认)
java -XX:+UseG1GC -jar app.jar

// ZGC(低延迟,JDK 11+)
java -XX:+UseZGC -jar app.jar

// Shenandoah(低延迟,JDK 12+)
java -XX:+UseShenandoahGC -jar app.jar
收集器算法停顿时间适用场景
Serial复制/标记-整理单核小内存
Parallel复制/标记-整理较长吞吐量优先
CMS标记-清除低延迟(已弃用)
G1标记-整理 + 复制可预测大堆平衡型
ZGC染色指针<10ms超大堆低延迟
ShenandoahBrooks 指针<10ms低延迟

3.4 内存泄漏示例

// 1. 静态集合导致的内存泄漏
public class MemoryLeak {
    private static final List<Object> list = new ArrayList<>();
    
    public void add(Object obj) {
        list.add(obj);  // 永远不会被释放
    }
}

// 2. 未关闭的资源
public void readFile(String path) throws IOException {
    // 错误:未关闭流
    BufferedReader reader = new BufferedReader(new FileReader(path));
    return reader.readLine();
}

// 正确:使用 try-with-resources
public void readFileCorrect(String path) throws IOException {
    try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
        return reader.readLine();
    }
}

四、多线程与并发

4.1 线程创建方式

// 方式 1:继承 Thread 类
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("Thread running");
    }
}

// 方式 2:实现 Runnable 接口(推荐)
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("Runnable running");
    }
}

// 方式 3:使用 Lambda(Java 8+)
Thread t = new Thread(() -> System.out.println("Lambda thread"));

// 方式 4:使用线程池(推荐)
ExecutorService executor = Executors.newFixedThreadPool(4);
executor.submit(() -> System.out.println("Pool thread"));

4.2 线程状态

NEW(新建)
   ↓ start()
RUNNABLE(可运行)
   ↓ wait() / join() / LockSupport.park()
WAITING(无限等待)
   ↓ notify() / notifyAll() / LockSupport.unpark()
RUNNABLE
   ↓ synchronized / lock.lock()
BLOCKED(阻塞)
   ↓ 获取锁成功
RUNNABLE
   ↓ sleep(time) / wait(time) / join(time)
TIMED_WAITING(限时等待)
   ↓ 时间到 / notify()
RUNNABLE
   ↓ run() 结束
TERMINATED(终止)

4.3 同步机制

public class SynchronizedExample {
    private int count = 0;
    private final Object lock = new Object();
    
    // 方式 1:synchronized 方法
    public synchronized void increment() {
        count++;
    }
    
    // 方式 2:synchronized 代码块
    public void incrementBlock() {
        synchronized (lock) {
            count++;
        }
    }
}

// Java 5+ 的 Lock 接口
public class LockExample {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();
    
    public void safeOperation() {
        lock.lock();
        try {
            // 临界区代码
            condition.await();  // 等待
            condition.signal(); // 唤醒
        } finally {
            lock.unlock();
        }
    }
}

4.4 并发工具类(JUC)

// 1. CountDownLatch - 等待多个线程完成
CountDownLatch latch = new CountDownLatch(3);
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 执行任务
        latch.countDown();
    }).start();
}
latch.await();  // 主线程等待

// 2. CyclicBarrier - 线程互相等待
CyclicBarrier barrier = new CyclicBarrier(3);
for (int i = 0; i < 3; i++) {
    new Thread(() -> {
        // 准备阶段
        barrier.await();  // 到达屏障,等待其他线程
        // 同时开始执行
    }).start();
}

// 3. Semaphore - 控制并发数量
Semaphore semaphore = new Semaphore(10);  // 最多10个并发
semaphore.acquire();   // 获取许可
// 执行操作
semaphore.release();   // 释放许可

// 4. CompletableFuture - 异步编程(Java 8+)
CompletableFuture.supplyAsync(() -> fetchData())
    .thenApply(data -> process(data))
    .thenAccept(result -> save(result))
    .exceptionally(ex -> { handle(ex); return null; });

4.5 volatile 与原子类

// volatile 保证可见性,但不保证原子性
private volatile boolean flag = false;

// 原子类保证原子操作
private AtomicInteger counter = new AtomicInteger(0);

public void increment() {
    counter.incrementAndGet();  // 原子自增
}

// CAS 操作原理
public boolean compareAndSet(int expect, int update) {
    // 如果当前值等于 expect,则更新为 update
}

五、异常处理机制

5.1 异常体系

Throwable
├── Error(严重错误,不处理)
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── ...
└── Exception(可处理异常)
    ├── RuntimeException(运行时异常,非受检)
    │   ├── NullPointerException
    │   ├── ArrayIndexOutOfBoundsException
    │   ├── IllegalArgumentException
    │   └── ...
    └── 其他 Exception(受检异常,必须处理)
        ├── IOException
        ├── SQLException
        └── ...

5.2 异常处理最佳实践

// 1. 精准捕获异常
try {
    processFile();
} catch (FileNotFoundException e) {
    // 文件不存在,提示用户
    logger.error("File not found: {}", filePath);
} catch (IOException e) {
    // IO 错误,可能需要重试
    logger.error("IO error: {}", e.getMessage());
}

// 2. 使用 try-with-resources(Java 7+)
try (InputStream in = new FileInputStream(file);
     OutputStream out = new FileOutputStream(dest)) {
    // 自动关闭资源
    copy(in, out);
} catch (IOException e) {
    logger.error("Copy failed", e);
}

// 3. 自定义异常
public class BusinessException extends RuntimeException {
    private final String errorCode;
    
    public BusinessException(String errorCode, String message) {
        super(message);
        this.errorCode = errorCode;
    }
    
    // 不要丢失堆栈信息
    public BusinessException(String message, Throwable cause) {
        super(message, cause);
    }
}

// 4. 异常转换
public void serviceMethod() {
    try {
        dao.operation();
    } catch (SQLException e) {
        // 转换为业务异常,隐藏底层细节
        throw new BusinessException("DB_ERROR", "数据库操作失败", e);
    }
}

六、泛型(Generics)

6.1 基本用法

// 泛型类
public class Box<T> {
    private T content;
    
    public void setContent(T content) {
        this.content = content;
    }
    
    public T getContent() {
        return content;
    }
}

// 使用
Box<String> stringBox = new Box<>();
stringBox.setContent("Hello");
String content = stringBox.getContent();  // 无需强制转换

// 泛型方法
public <T> void printArray(T[] array) {
    for (T element : array) {
        System.out.println(element);
    }
}

6.2 通配符

// ? extends T - 上界通配符(只读)
public void process(List<? extends Number> list) {
    Number n = list.get(0);  // 可以读取
    // list.add(1);  // 编译错误,不能写入
}

// ? super T - 下界通配符(只写)
public void addNumbers(List<? super Integer> list) {
    list.add(1);  // 可以写入
    // Integer i = list.get(0);  // 编译错误,读取只能是 Object
}

// PECS 原则
// Producer Extends, Consumer Super

6.3 类型擦除

// 编译前
List<String> strList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();

// 编译后(类型擦除)
List strList = new ArrayList();
List intList = new ArrayList();

// 运行时无法获取泛型类型
System.out.println(strList.getClass() == intList.getClass());  // true

七、反射机制

7.1 获取 Class 对象

// 方式 1
Class<?> clazz1 = String.class;

// 方式 2
Class<?> clazz2 = "hello".getClass();

// 方式 3
Class<?> clazz3 = Class.forName("java.lang.String");

7.2 反射操作

public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = User.class;
        
        // 创建实例
        User user = (User) clazz.getDeclaredConstructor().newInstance();
        
        // 获取方法
        Method method = clazz.getDeclaredMethod("setName", String.class);
        method.invoke(user, "Alice");
        
        // 获取字段
        Field field = clazz.getDeclaredField("age");
        field.setAccessible(true);  // 访问私有字段
        field.setInt(user, 25);
        
        // 获取注解
        Annotation[] annotations = clazz.getAnnotations();
    }
}

7.3 反射的应用与注意

应用场景:

  • 框架开发(Spring、MyBatis)
  • 序列化/反序列化
  • 动态代理
  • 单元测试

注意事项:

  • 性能开销较大(绕过编译优化)
  • 破坏封装性
  • 类型安全性降低

八、Java 8+ 新特性

8.1 Lambda 表达式

// 传统写法
Comparator<String> comparator = new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }
};

// Lambda 写法
Comparator<String> lambda = (s1, s2) -> s1.length() - s2.length();

// 方法引用
Comparator<String> methodRef = Comparator.comparingInt(String::length);

8.2 Stream API

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

// 过滤、映射、收集
List<Integer> result = numbers.stream()
    .filter(n -> n > 5)           // 过滤大于5的
    .map(n -> n * 2)              // 乘以2
    .sorted(Comparator.reverseOrder())  // 降序排序
    .limit(3)                     // 取前3个
    .collect(Collectors.toList());

// 聚合操作
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
int max = numbers.stream().mapToInt(Integer::intValue).max().orElse(0);

// 分组
Map<String, List<Person>> groups = people.stream()
    .collect(Collectors.groupingBy(Person::getCity));

8.3 Optional

// 避免空指针异常
public String getCity(User user) {
    return Optional.ofNullable(user)
        .map(User::getAddress)
        .map(Address::getCity)
        .orElse("Unknown");
}

// 不要这样用(违背设计目的)
Optional<User> user = ...;  // 作为字段或参数
if (user.isPresent()) {     // 不要用 isPresent + get
    ...
}

8.4 新日期时间 API

// 旧 API(线程不安全,设计差)
Date date = new Date();
Calendar calendar = Calendar.getInstance();

// 新 API(Java 8+)
LocalDate today = LocalDate.now();
LocalTime now = LocalTime.now();
LocalDateTime dateTime = LocalDateTime.now();

// 时区处理
ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));

// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = dateTime.format(formatter);

// 计算
LocalDate nextWeek = today.plusWeeks(1);
Period period = Period.between(startDate, endDate);
Duration duration = Duration.between(startTime, endTime);

8.5 接口默认方法

public interface Animal {
    void eat();  // 抽象方法
    
    default void breathe() {  // 默认方法
        System.out.println("Breathing...");
    }
    
    static void info() {  // 静态方法
        System.out.println("This is an animal");
    }
}

九、模块系统(Java 9+)

9.1 模块化概述

myapp/
├── src/
│   └── com.myapp/
│       ├── module-info.java
│       └── com/myapp/
│           └── Main.java
└── lib/
    └── com.modules.utilities.jar

9.2 module-info.java

module com.myapp {
    // 依赖的模块
    requires java.base;  // 默认隐式依赖
    requires java.sql;
    requires com.modules.utilities;
    
    // 导出的包(对外可见)
    exports com.myapp.api;
    
    // 开放反射访问
    opens com.myapp.internal;
    
    // 服务提供/消费
    provides com.myapp.spi.Service 
        with com.myapp.impl.ServiceImpl;
    uses com.myapp.spi.Service;
}

十、Java 21 新特性(LTS)

Java 21 是长期支持(LTS)版本,带来了革命性的并发编程模型改进,其中最引人注目的是**虚拟线程(Virtual Threads)**正式成为标准特性。

10.1 虚拟线程(Virtual Threads)

传统线程 vs 虚拟线程

特性传统线程(Platform Thread)虚拟线程(Virtual Thread)
实现方式1:1 映射到 OS 线程JVM 调度,多对多映射
内存占用~1-2 MB 栈空间~几百字节
创建速度慢(需系统调用)快(纯 JVM 操作)
数量限制数千级别数百万级别
阻塞影响阻塞会占用 OS 线程阻塞时自动让出载体线程
适用场景计算密集型I/O 密集型

虚拟线程原理

┌─────────────────────────────────────────────────────────┐
│                      Java 应用层                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐      │
│  │  虚拟线程    │  │  虚拟线程    │  │  虚拟线程    │ ... │
│  │  Virtual    │  │  Virtual    │  │  Virtual    │     │
│  │   Thread    │  │   Thread    │  │   Thread    │     │
│  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘      │
│         └─────────────────┼─────────────────┘             │
│                           │                              │
│              JVM 调度器(ForkJoinPool)                    │
│                           │                              │
│  ┌────────────────────────┼────────────────────────┐    │
│  │      载体线程(Carrier Thread / Platform Thread)   │    │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐       │    │
│  │  │ Carrier 1│  │ Carrier 2│  │ Carrier N│       │    │
│  │  └──────────┘  └──────────┘  └──────────┘       │    │
│  └──────────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────────┘
              ┌────────────┴────────────┐
              ▼                         ▼
        ┌──────────┐              ┌──────────┐
        │ OS 线程 1 │              │ OS 线程 N │
        └──────────┘              └──────────┘

虚拟线程使用方式

// 方式 1:使用 Thread.ofVirtual()(Java 21+)
Thread.startVirtualThread(() -> {
    System.out.println("Running in virtual thread: " + 
        Thread.currentThread());
});

// 方式 2:使用 ExecutorService
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));  // 阻塞操作
            return i;
        });
    });
}  // executor.close() 会等待所有任务完成

// 方式 3:ThreadFactory
ThreadFactory factory = Thread.ofVirtual().factory();
Thread vThread = factory.newThread(() -> {
    // 任务代码
});
vThread.start();

性能对比示例

public class ThreadComparison {
    
    // 传统线程池处理 10000 个任务
    public static void platformThreads() throws InterruptedException {
        try (var executor = Executors.newFixedThreadPool(100)) {
            long start = System.currentTimeMillis();
            
            for (int i = 0; i < 10_000; i++) {
                executor.submit(() -> {
                    Thread.sleep(100);  // 模拟 I/O
                    return 0;
                });
            }
            
            System.out.println("Platform threads: " + 
                (System.currentTimeMillis() - start) + "ms");
        }
    }
    
    // 虚拟线程处理 10000 个任务
    public static void virtualThreads() throws InterruptedException {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            long start = System.currentTimeMillis();
            
            for (int i = 0; i < 10_000; i++) {
                executor.submit(() -> {
                    Thread.sleep(100);  // 阻塞时自动让出
                    return 0;
                });
            }
            
            System.out.println("Virtual threads: " + 
                (System.currentTimeMillis() - start) + "ms");
        }
    }
}

典型输出:

Platform threads: 10000ms+  (线程池限制)
Virtual threads:  200ms     (几乎同时调度)

虚拟线程注意事项

// ⚠️ 不要这样做:在虚拟线程中使用 synchronized
virtualThread.execute(() -> {
    synchronized (lock) {  // 会 "钉住" 载体线程(Pinning)
        // 长时间操作
    }
});

// ✅ 推荐:使用 ReentrantLock
virtualThread.execute(() -> {
    lock.lock();  // 不会钉住载体线程
    try {
        // 操作
    } finally {
        lock.unlock();
    }
});

// ⚠️ 线程本地变量(ThreadLocal)在虚拟线程中开销大
// Java 21 引入了 ScopedValue 作为替代

10.2 结构化并发(Structured Concurrency)

结构化并发让多线程编程像单线程一样清晰,子任务与父任务有明确的生命周期关系。

// Java 21 预览特性(需要 --enable-preview)
import java.util.concurrent.StructuredTaskScope;

public class StructuredConcurrencyDemo {
    
    record User(String name, int orderCount) {}
    record Order(String id, double amount) {}
    
    // 传统写法:容易忘记关闭资源,异常处理复杂
    public User fetchUserOldStyle(String userId) throws Exception {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Future<User> userFuture = executor.submit(() -> fetchUser(userId));
        Future<Order> orderFuture = executor.submit(() -> fetchLatestOrder(userId));
        
        User user = userFuture.get();  // 可能永远阻塞
        Order order = orderFuture.get();
        
        executor.shutdown();  // 容易遗漏
        return new User(user.name(), order != null ? 1 : 0);
    }
    
    // 结构化并发写法
    public User fetchUserStructured(String userId) throws Exception {
        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
            // 启动子任务
            StructuredTaskScope.Subtask<User> userTask = 
                scope.fork(() -> fetchUser(userId));
            StructuredTaskScope.Subtask<Order> orderTask = 
                scope.fork(() -> fetchLatestOrder(userId));
            
            // 等待所有任务完成或失败
            scope.join();
            scope.throwIfFailed();  // 任一失败则抛出异常
            
            // 获取结果
            return new User(userTask.get().name(), 
                orderTask.get() != null ? 1 : 0);
        }  // 自动关闭,取消未完成任务
    }
    
    // 成功即返回模式(竞赛模式)
    public String fetchFastest() throws Exception {
        try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
            scope.fork(() -> fetchFromServerA());
            scope.fork(() -> fetchFromServerB());
            scope.fork(() -> fetchFromServerC());
            
            scope.join();
            return scope.result();  // 返回最先成功的结果
        }
    }
}

结构化并发优势:

  • 清晰的错误传播:子任务失败,父任务自动取消其他子任务
  • 确定的生命周期:try-with-resources 确保资源释放
  • 可观测性:任务关系明确,便于调试

10.3 Record Patterns(记录模式)

Java 21 扩展了模式匹配,支持直接解构 Record 类。

// 定义记录
record Point(int x, int y) {}
record ColoredPoint(Point point, String color) {}

public class RecordPatternDemo {
    
    // Java 17 写法
    public void printPointOld(Object obj) {
        if (obj instanceof Point p) {
            int x = p.x();
            int y = p.y();
            System.out.println("x=" + x + ", y=" + y);
        }
    }
    
    // Java 21 写法:直接解构
    public void printPoint(Object obj) {
        if (obj instanceof Point(int x, int y)) {
            System.out.println("x=" + x + ", y=" + y);
            // 无需通过 p.x() 访问
        }
    }
    
    // 嵌套解构
    public void printColoredPoint(Object obj) {
        if (obj instanceof ColoredPoint(Point(int x, int y), String color)) {
            System.out.println("Point at (" + x + "," + y + ") is " + color);
        }
    }
    
    // 在 switch 中使用
    public String describe(Object obj) {
        return switch (obj) {
            case Point(int x, int y) when x == 0 && y == 0 -> "原点";
            case Point(int x, int y) when x == y -> "对角线上的点";
            case Point(int x, _) when x < 0 -> "左侧的点";
            case Point(_, int y) when y < 0 -> "下方的点";
            case Point(int x, int y) -> "普通点 (" + x + "," + y + ")";
            default -> "未知";
        };
    }
}

10.4 Switch 模式匹配(标准特性)

Java 21 将 Switch 的模式匹配提升为标准特性。

public class SwitchPatternDemo {
    
    // 类型模式 + null 处理 + 守卫条件
    public String formatter(Object obj) {
        return switch (obj) {
            case null -> "null";
            case Integer i when i > 0 -> "正整数: " + i;
            case Integer i when i < 0 -> "负整数: " + i;
            case Integer i -> "零";
            case Long l -> "长整数: " + l;
            case String s when s.isEmpty() -> "空字符串";
            case String s when s.length() > 10 -> "长字符串: " + s.substring(0, 10) + "...";
            case String s -> "字符串: " + s;
            case List<?> list when list.isEmpty() -> "空列表";
            case List<?> list -> "包含 " + list.size() + " 个元素的列表";
            default -> "未知类型: " + obj.getClass().getName();
        };
    }
    
    // 枚举穷尽匹配(无需 default)
    enum Direction { NORTH, SOUTH, EAST, WEST }
    
    public String directionName(Direction d) {
        return switch (d) {
            case NORTH -> "北";
            case SOUTH -> "南";
            case EAST -> "东";
            case WEST -> "西";
            // 无需 default,编译器会检查穷尽性
        };
    }
}

10.5 顺序集合(Sequenced Collections)

Java 21 引入了统一的顺序集合接口。

// 新接口层次
// SequencedCollection extends Collection
// ├── SequencedSet extends SequencedCollection, Set
// └── SequencedMap extends Map

public void sequencedDemo() {
    // List 本身就是有序的
    List<String> list = new ArrayList<>();
    list.addLast("B");  // 新增默认方法
    list.addFirst("A");
    String first = list.getFirst();  // "A"
    String last = list.getLast();    // "B"
    
    // LinkedHashSet 现在支持顺序操作
    SequencedSet<String> set = new LinkedHashSet<>();
    set.add("A");
    set.add("B");
    set.add("C");
    
    SequencedSet<String> reversed = set.reversed();  // 反向视图
    // reversed: C, B, A
    
    // LinkedHashMap 支持顺序操作
    SequencedMap<Integer, String> map = new LinkedHashMap<>();
    map.putFirst(1, "A");  // 插入头部
    map.putLast(2, "B");   // 插入尾部(等价于 put)
    
    Map.Entry<Integer, String> firstEntry = map.firstEntry();
    Map.Entry<Integer, String> lastEntry = map.lastEntry();
}

10.6 String Templates(预览特性)

// 更安全的字符串拼接
public class StringTemplateDemo {
    
    // 传统方式:容易 SQL 注入
    public String buildQueryUnsafe(String userId) {
        return "SELECT * FROM users WHERE id = '" + userId + "'";
        // 如果 userId = "' OR '1'='1" 会导致注入
    }
    
    // Java 21 字符串模板(STR 处理器)
    public String buildQuerySafe(String userId) {
        // 自动转义,防止注入
        return STR."SELECT * FROM users WHERE id = \"\{userId}\"";
    }
    
    // JSON 构造
    public String buildJson(String name, int age) {
        return STR."""
            {
                "name": "\{name}",
                "age": \{age}
            }
            """;
    }
    
    // 自定义处理器
    public void customProcessor() {
        // FMT:格式化处理器
        String formatted = FMT."Price: %10.2f\{price}";
        
        // RAW:原始处理器(返回 StringTemplate 对象)
        StringTemplate template = RAW."Hello \{name}";
    }
}

10.7 Java 21 与之前版本对比总结

特性Java 8Java 11Java 17Java 21
Lambda✅ 新增
Stream✅ 新增
Optional✅ 新增
模块系统✅ 标准
var 推断
文本块
Switch 表达式
密封类✅ 标准
模式匹配 instanceof
虚拟线程✅ 标准
结构化并发✅ 预览
Record 模式✅ 标准
Switch 模式匹配预览✅ 标准
字符串模板✅ 预览

10.8 虚拟线程最佳实践

@Service
public class UserService {
    
    private final HttpClient httpClient = HttpClient.newHttpClient();
    
    // ✅ 适合虚拟线程:I/O 密集型
    public List<User> fetchUsersAsync(List<String> userIds) {
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            return userIds.stream()
                .map(id -> executor.submit(() -> fetchUser(id)))
                .toList()
                .stream()
                .map(CompletableFuture::join)
                .collect(Collectors.toList());
        }
    }
    
    // ❌ 不适合:计算密集型(占用 CPU)
    public BigInteger calculateFibonacci(int n) {
        // 纯计算任务,虚拟线程无优势
        // 应使用普通线程池
    }
    
    // ✅ 混合场景:I/O + 计算分离
    public Result processData(List<String> urls) {
        // I/O 部分用虚拟线程
        List<Data> dataList;
        try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
            dataList = urls.stream()
                .map(url -> executor.submit(() -> download(url)))
                .map(future -> {
                    try { return future.get(); }
                    catch (Exception e) { throw new RuntimeException(e); }
                })
                .collect(Collectors.toList());
        }
        
        // 计算部分用并行流(CPU 密集型)
        return dataList.parallelStream()
            .map(this::heavyComputation)
            .collect(Collectors.collectingAndThen(
                Collectors.toList(),
                this::mergeResults
            ));
    }
}

十一、总结

特性类别核心优势学习重点
面向对象封装、继承、多态、抽象设计原则、设计模式
跨平台JVM 字节码JVM 内存结构、类加载机制
内存管理自动垃圾回收GC 算法、调优参数
多线程丰富的并发工具JUC 包、线程池、锁优化
异常处理结构化异常机制异常设计、最佳实践
泛型类型安全、代码复用通配符、类型擦除
反射动态能力框架原理、性能权衡
函数式简洁、并行Stream、Lambda、Optional
虚拟线程 (Java 21)轻量级、高并发适用场景、结构化并发
模式匹配 (Java 21)简洁类型检查Record/Sealed Class 模式

参考资源: