Java 11-21 新特性盘点:var、record、sealed、虚拟线程

Java 11-21 新特性盘点:var、record、sealed、虚拟线程

Java 从 11 到 21 发生了翻天覆地的变化。从 var 局部变量推断到虚拟线程,每一个特性都在让 Java 更现代、更高效。本文盘点这 10 个版本的核心特性。

一、各版本特性全景

scss 复制代码
┌─────────────────────────────────────────────────────────┐
│              Java 11-21 核心特性演进                       │
├─────────────────────────────────────────────────────────┤
│                                                         │
│  Java 11 (LTS)  ── var 局部变量推断、HTTP Client、      │
│                    String API 增强、单文件程序          │
│                                                         │
│  Java 14       ── Switch 表达式(标准)、record 预览        │
│                                                         │
│  Java 15       ── 文本块(标准)、密封类预览、ZGC 生产级   │
│                                                         │
│  Java 16       ── record(标准)、Pattern Matching 预览    │
│                                                         │
│  Java 17 (LTS) ── 密封类(标准)、Pattern Matching for    │
│                    instanceof(标准)、强封装              │
│                                                         │
│  Java 19       ── 虚拟线程(预览)、结构化并发(预览)       │
│                                                         │
│  Java 21 (LTS) ── 虚拟线程(标准)、Pattern Matching for  │
│                    switch(标准)、序列集合、记录模式      │
│                                                         │
└─────────────────────────────────────────────────────────┘

二、var 局部变量类型推断(Java 11)

java 复制代码
// Java 10 引入,Java 11 作为 LTS 包含

// 之前
Map<String, List<User>> users = new HashMap<>();
Stream<String> stream = users.keySet().stream();

// 现在
var users = new HashMap<String, List<User>>();
var stream = users.keySet().stream();
// 类型自动推断,代码更简洁
java 复制代码
// var 只能用于局部变量,不能用于字段、方法参数、返回值

// ✅ 可以
var list = new ArrayList<String>();
var map = new HashMap<String, User>();
var result = process(data);
var stream = list.stream().filter(x -> x > 0).map(x -> x * 2);

// ❌ 不可以
// private var field = "hello";        // 字段
// public var process() { return 1; } // 返回值
// public void test(var param) { }    // 参数

// 注意: var 不是动态类型,编译期已确定类型
var x = 1;    // x 是 int
x = "hello";  // 编译错误! x 是 int 不能赋 String

三、record 记录类(Java 16 标准)

java 复制代码
// 之前: 写一个数据类需要大量样板代码
public class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() { return x; }
    public int getY() { return y; }

    @Override
    public boolean equals(Object o) { /* ... */ }

    @Override
    public int hashCode() { /* ... */ }

    @Override
    public String toString() { /* ... */ }
}

// 现在: 一行搞定
public record Point(int x, int y) {}
// 自动生成: 构造器、getter(x(), y())、equals、hashCode、toString
java 复制代码
// record 特性
record User(String name, int age, String email) {
    // 紧凑构造器 (验证逻辑)
    public User {
        if (age < 0) throw new IllegalArgumentException("age");
        if (email == null) email = "";
    }

    // 自定义方法
    public boolean isAdult() {
        return age >= 18;
    }

    // 不可变: 没有 setter
    // 继承: record 隐式 final,不能被继承
    // 实现接口: 可以
}

// 使用
User user = new User("Tom", 20, "tom@test.com");
user.name();     // "Tom" (注意不是 getName())
user.age();      // 20
user.isAdult();  // true
user.equals(new User("Tom", 20, "tom@test.com")); // true
arduino 复制代码
record vs 传统数据类:

  ┌──────────────┬───────────────┐
  │   record      │  传统 class    │
  ├──────────────┼───────────────┤
  │ 不可变        │ 可变/不可变     │
  │ 自动生成方法   │ 手动编写       │
  │ 隐式 final   │ 可继承         │
  │ 不能继承       │ 可以继承      │
  │ 可实现接口     │ 可实现接口     │
  │ 适合 DTO      │ 适合实体类     │
  └──────────────┴───────────────┘

四、sealed 密封类(Java 17 标准)

java 复制代码
// 密封类: 控制哪些类可以继承/实现
public sealed interface Shape
    permits Circle, Square, Rectangle {}

// 子类必须是 final、sealed 或 non-sealed
record Circle(double radius) implements Shape {}
record Square(double side) implements Shape {}
non-sealed class Rectangle implements Shape {}
// Rectangle 的子类不受限制

// ❌ 其他类不能实现 Shape
// record Triangle(double base, double height) implements Shape {}
// 编译错误: Triangle 不在 permits 列表中
java 复制代码
密封类层级:

  sealed interface Shape
    ├── permits Circle    → record (隐式 final)
    ├── permits Square    → record (隐式 final)
    └── permits Rectangle → non-sealed (可被任意继承)
        ├── CustomRectangle
        └── RoundedRectangle

  密封类的价值:
  ├── 编译期知道所有子类 → 支持穷尽检查
  ├── Pattern Matching switch 可以省略 default
  └── 防止滥用继承,控制类型层次

五、Pattern Matching(Java 17+ 21)

1. instanceof 模式匹配(Java 17 标准)

java 复制代码
// 之前
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.length());
}

// 现在: 直接绑定变量
if (obj instanceof String s) {
    System.out.println(s.length());
    // s 在此作用域内可用
}

// 作用域: 流敏感
if (obj instanceof String s && s.length() > 5) {
    // s 在 && 右侧已可用
    System.out.println(s);
}

if (!(obj instanceof String s)) {
    // s 不可用 (取反)
    return;
}
// s 可用 (此处已确保是 String)
System.out.println(s);

2. switch 模式匹配(Java 21 标准)

java 复制代码
// 传统 switch: 只能匹配常量
switch (day) {
    case MONDAY: case FRIDAY: return 5;
    case TUESDAY: case THURSDAY: return 6;
    default: return 0;
}

// 新 switch: 模式匹配 + 表达式
String formatted = switch (obj) {
    case Integer i -> "int: " + i;
    case String s -> "str: " + s;
    case null -> "null";
    default -> "unknown";
};

// 配合密封类: 穷尽检查
sealed interface Shape permits Circle, Square, Rectangle {}

double area = switch (shape) {
    case Circle c -> Math.PI * c.radius() * c.radius();
    case Square s -> s.side() * s.side();
    case Rectangle r -> r.width() * r.height();
    // 不需要 default! 编译器知道已穷尽所有情况
};

3. 记录模式(Java 21)

java 复制代码
// 解构 record
record Point(int x, int y) {}
record Line(Point start, Point end) {}

void printLine(Object obj) {
    if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
        System.out.printf("(%d,%d) -> (%d,%d)%n", x1, y1, x2, y2);
    }
}

// 嵌套解构
if (obj instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
    double length = Math.sqrt(Math.pow(x2-x1, 2) + Math.pow(y2-y1, 2));
}

// switch 中的记录模式
String describe = switch (shape) {
    case Circle(double r) when r > 100 -> "large circle";
    case Circle(double r) -> "small circle, r=" + r;
    case Square(double s) -> "square, side=" + s;
};

六、文本块(Java 15 标准)

java 复制代码
// 之前: 大量转义和拼接
String json = "{\n" +
    "  \"name\": \"Tom\",\n" +
    "  \"age\": 20\n" +
    "}";

// 现在: 文本块
String json = """
        {
          "name": "Tom",
          "age": 20
        }
        """;

// 可选的转义处理
String sql = """
    SELECT * FROM users \
    WHERE age > 18 \
    ORDER BY name
    """;  // \ 表示行连接(续行)
java 复制代码
// 字符串模板 (Java 21 预览, 后续版本移除)
// 注意: 字符串模板在 Java 21 预览后被撤回, 不推荐使用
// var name = "Tom";
// var msg = STR."Hello \{name}"; // 预览特性,暂不稳定

七、虚拟线程(Java 21 标准)

java 复制代码
// 虚拟线程: 轻量级线程,由 JVM 调度,不是 OS 线程

// 创建平台线程 (传统)
Thread thread = new Thread(() -> {
    System.out.println("Platform Thread: " + Thread.currentThread());
});

// 创建虚拟线程
Thread vThread = Thread.ofVirtual().start(() -> {
    System.out.println("Virtual Thread: " + Thread.currentThread());
});

// 通过 Executors
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
} // 10000 个虚拟线程,几乎不消耗额外内存
less 复制代码
平台线程 vs 虚拟线程:

  ┌──────────────────┬──────────────────┐
  │   平台线程         │   虚拟线程        │
  ├──────────────────┼──────────────────┤
  │ OS 线程 (1:1)     │ JVM 调度 (N:M)    │
  │ 栈 ~1MB           │ 栈 ~KB 级         │
  │ 创建开销大        │ 创建开销极小      │
  │ 数量受 OS 限制    │ 数量可达百万级    │
  │ 阻塞→OS 切换     │ 阻塞→JVM 切换    │
  │ 适合 CPU 密集    │ 适合 IO 密集      │
  └──────────────────┴──────────────────┘

  虚拟线程执行模型:
  
  虚拟线程#1 ─┐
  虚拟线程#2 ─┤  JVM 调度器 (ForkJoinPool)
  虚拟线程#N ─┘         │
                        ▼
                   平台线程 (Carrier)
                   ┌─────┬─────┬─────┐
                   │ CT1 │ CT2 │ CT3 │  ← 少量载体线程
                   └─────┴─────┴─────┘
                   
  虚拟线程在 IO 阻塞时:
    1. JVM 将虚拟线程从载体线程卸载
    2. 载体线程可以执行其他虚拟线程
    3. IO 完成后, 虚拟线程重新挂载到载体线程

虚拟线程的适用场景和限制

java 复制代码
// ✅ 适合: IO 密集型
Thread.ofVirtual().start(() -> {
    var response = httpClient.send(request, BodyHandlers.ofString()); // 阻塞 IO
    process(response);
});

// ✅ 适合: 高并发 Web 服务器
// Spring Boot 3.2+ 支持虚拟线程
// spring.threads.virtual.enabled=true

// ❌ 不适合: CPU 密集型
Thread.ofVirtual().start(() -> {
    // 计算密集任务不会释放载体线程
    // 虚拟线程优势消失
    heavyComputation();
});

// ⚠️ 注意: synchronized 会 pin 虚拟线程
// 虚拟线程在 synchronized 块中阻塞时不能被卸载
// 建议: 用 ReentrantLock 替代 synchronized
Thread.ofVirtual().start(() -> {
    // ❌ synchronized 会 pin 虚拟线程
    synchronized(lock) {
        blockingIO(); // 载体线程被占用!
    }

    // ✅ ReentrantLock 不会 pin
    lock.lock();
    try {
        blockingIO(); // 虚拟线程可卸载
    } finally {
        lock.unlock();
    }
});

八、其他重要特性

Switch 表达式(Java 14 标准)

java 复制代码
// switch 表达式 + 箭头语法
int days = switch (month) {
    case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> 31;
    case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
    case FEBRUARY -> isLeapYear ? 29 : 28;
    default -> throw new IllegalArgumentException();
};

// yield 返回值
int result = switch (x) {
    case 1, 2, 3 -> x * 10;
    default -> {
        log("default: " + x);
        yield x * 100;
    }
};

序列集合(Java 21)

java 复制代码
// SequencedCollection: 有明确遇见顺序的集合
interface SequencedCollection<E> extends Collection<E> {
    E getFirst();              // 第一个元素
    E getLast();               // 最后一个元素
    void addFirst(E e);         // 头部添加
    void addLast(E e);          // 尾部添加
    E removeFirst();            // 移除第一个
    E removeLast();             // 移除最后一个
    SequencedCollection<E> reversed(); // 反转视图
}

// List, Deque 等都是 SequencedCollection
List<Integer> list = List.of(1, 2, 3, 4, 5);
list.getFirst();  // 1
list.getLast();   // 5
list.reversed();  // [5, 4, 3, 2, 1]

LinkedHashSet<Integer> set = new LinkedHashSet<>(List.of(1, 2, 3));
set.getFirst(); // 1 (LinkedHashSet 是 SequencedSet)

结构化并发(Java 21 预览)

java 复制代码
// 结构化并发: 父子线程生命周期绑定
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    // 并发执行多个子任务
    Subtask<User> userTask = scope.fork(() -> fetchUser(id));
    Subtask<Order> orderTask = scope.fork(() -> fetchOrder(id));

    scope.join();              // 等待所有子任务完成
    scope.throwIfFailed();     // 任一失败则抛异常

    // 所有成功
    User user = userTask.get();
    Order order = orderTask.get();
    return new UserOrder(user, order);
} // 退出 scope 时自动关闭所有子任务

九、各版本特性速查表

版本 特性 语法
Java 11 var var x = 1;
Java 14 switch 表达式 var r = switch(x) { case 1 -> "a"; };
Java 15 文本块 """text"""
Java 16 record record Point(int x, int y) {}
Java 17 sealed sealed interface Shape permits Circle
Java 17 instanceof PM if (obj instanceof String s)
Java 21 虚拟线程 Thread.ofVirtual().start(r)
Java 21 switch PM case Integer i -> ...
Java 21 记录模式 case Point(var x, var y)
Java 21 序列集合 list.getFirst()

十、常见面试追问

Q1:record 和 Lombok @Data 有什么区别?

record 是语言级特性,生成的类不可变且隐式 final。Lombok @Data 是编译期字节码注入,生成的是可变类(有 setter),且类可以被继承。record 适合 DTO,Lombok @Data 适合实体类。

Q2:sealed 类有什么实际用途?

  1. 配合 Pattern Matching switch 实现穷尽检查(不需要 default)
  2. 领域建模时控制继承层次
  3. 编译器可检查遗漏的 case

Q3:虚拟线程能完全替代线程池吗?

不能完全替代。虚拟线程适合 IO 密集型场景,CPU 密集型任务仍应使用平台线程。而且虚拟线程本身不限制并发数,仍需要信号量控制对共享资源的访问。

Q4:虚拟线程和 Reactor/CompletableFuture 怎么选?

虚拟线程用同步代码风格实现异步效果,代码更简单可读。CompletableFuture/Reactor 更灵活(组合、超时、回调),但编程复杂。新项目建议优先用虚拟线程。

十一、总结

java 复制代码
Java 11-21 核心演进:

  语法简化: var → record → sealed → text block
  类型安全: Pattern Matching (instanceof → switch → record pattern)
  并发革命: 虚拟线程 (同步代码风格 + 异步性能)
  集合增强: 序列集合 (getFirst/getLast/reversed)

  设计哲学:
    record: 数据类不可变 + 样板代码消除
    sealed: 控制继承 + 编译期穷尽检查
    虚拟线程: 同步编程模型 + 高并发能力
    Pattern Matching: 类型安全 + 代码简化

Java 11-21 的演进方向清晰:减少样板代码、增强类型安全、简化并发编程。从 record 到虚拟线程,每个特性都在让 Java 更现代化,同时也保持了向后兼容的核心承诺。

相关推荐
TangGeeA1 小时前
命令安全设置
java·服务器·安全
欣栀♡1 小时前
Spring 循环依赖不止三级缓存,Boot 2.6 起这个开关默认已经关了
java·spring·缓存
SL_staff1 小时前
3分钟上线新规则:业务人员拖拽完成合同超期自动暂停服务
java·mysql·全栈
Android小码家1 小时前
Vehicle 实战 自定义属性+测试demo
java·c++·framework·vhal·vehicle
范同学~1 小时前
固定表头+第一列+最后一列
java·服务器·前端
随风爱学习2 小时前
JAVA学习之异常
java
m0_639906942 小时前
HashMap:哈希扰动、扩容源码、红黑树转换、并发问题
java·算法·哈希算法
Roll圈圈2 小时前
长链接太丑影响转化率?这个短链工具让你的推广链接更专业
java
神魔皆以血嗜2 小时前
Java 存储金额
java·后端