JDK 8 到 JDK 24 更新内容详解
本文档详细介绍从 JDK 8 到 JDK 24 的所有重大更新内容和新特性。
目录
- 一、版本更新概览
- 二、语言特性详解
- 1. Lambda 表达式 (JDK 8)
- 2. Stream API (JDK 8+)
- 3. Optional (JDK 8+)
- 4. 新日期时间 API (JDK 8)
- 5. var 局部变量类型推断 (JDK 10)
- 6. 文本块 Text Blocks (JDK 15)
- 7. Records 记录类 (JDK 16)
- 8. Sealed Classes 密封类 (JDK 17)
- 9. Pattern Matching 模式匹配
- 10. Unnamed Variables 未命名变量 (JDK 22)
- 11. 集合工厂方法 (JDK 9)
- 12. Sequenced Collections (JDK 21)
- 三、并发编程特性
- 四、API 和工具改进
- 五、垃圾收集器演进
- 六、其他重要改进
- 七、总结
一、版本更新概览
JDK 8 (2014.03) - LTS ⭐
- Lambda 表达式 - 函数式编程基础
- Stream API - 集合流式处理
- Optional - 优雅处理空值
- 新日期时间 API -
java.time包 - 默认方法 - 接口可以有默认实现
- 方法引用 -
::操作符 - Nashorn JavaScript 引擎
JDK 9 (2017.09)
- 模块系统 (Jigsaw) -
module-info.java - JShell - 交互式 REPL 工具
- 集合工厂方法 -
List.of(),Set.of(),Map.of() - 接口私有方法
- Stream API 增强 -
takeWhile,dropWhile,ofNullable - Optional 增强 -
ifPresentOrElse,or,stream - Process API 改进
- HTTP/2 Client (孵化)
JDK 10 (2018.03)
- 局部变量类型推断 -
var关键字 - G1 GC 并行 Full GC
- 应用类数据共享 (Application CDS)
- 线程局部握手
- Optional.orElseThrow() 无参版本
JDK 11 (2018.09) - LTS ⭐
- HTTP Client 正式版 - 支持 HTTP/2 和 WebSocket
- String 新方法 -
isBlank(),lines(),strip(),repeat() - Files 新方法 -
readString(),writeString() - Lambda 中使用 var
- 单文件源码运行 -
java Hello.java - 移除 Java EE 和 CORBA 模块
- ZGC (实验性) - 低延迟垃圾收集器
- Flight Recorder 开源
JDK 12 (2019.03)
- Switch 表达式 (预览)
- Shenandoah GC (实验性)
- JVM 常量 API
- 微基准测试套件
- G1 可中断 Mixed GC
JDK 13 (2019.09)
- 文本块 (预览) -
"""多行字符串""" - Switch 表达式 (第二次预览)
- ZGC 改进 - 返还未使用内存
- Socket API 重新实现
- 动态 CDS 归档
JDK 14 (2020.03)
- Switch 表达式 (正式)
- instanceof 模式匹配 (预览) -
if (obj instanceof String s) - Records (预览) - 不可变数据类
- NullPointerException 增强 - 更详细的错误信息
- 文本块 (第二次预览)
- G1 支持 NUMA
- 移除 CMS 垃圾收集器
- ZGC 支持 macOS 和 Windows
JDK 15 (2020.09)
- 文本块 (正式)
- Sealed Classes (预览) - 密封类
- Hidden Classes - 隐藏类
- Records (第二次预览)
- instanceof 模式匹配 (第二次预览)
- ZGC 和 Shenandoah 正式发布
- 移除 Nashorn JavaScript 引擎
- Edwards-Curve 数字签名算法
JDK 16 (2021.03)
- Records (正式)
- instanceof 模式匹配 (正式)
- Sealed Classes (第二次预览)
- Vector API (孵化) - SIMD 支持
- Foreign Linker API (孵化)
- 打包工具 jpackage
- Unix-Domain Socket Channels
- Alpine Linux 移植
JDK 17 (2021.09) - LTS ⭐
- Sealed Classes (正式)
- Pattern Matching for switch (预览)
- 强封装 JDK 内部 API
- 移除 RMI Activation
- 移除实验性 AOT 和 JIT 编译器
- 弃用 Security Manager
- Foreign Function & Memory API (孵化)
- Context-Specific Deserialization Filters
- macOS/AArch64 移植
JDK 18 (2022.03)
- 默认 UTF-8 字符集
- 简单 Web 服务器 -
jwebserver命令 - 代码片段 API -
@snippetJavaDoc 标签 - Pattern Matching for switch (第二次预览)
- Vector API (第三次孵化)
- 互联网地址解析 SPI
- 弃用 Finalization
JDK 19 (2022.09)
- 虚拟线程 (预览) - Project Loom
- 结构化并发 (孵化)
- Record Patterns (预览)
- Pattern Matching for switch (第三次预览)
- Foreign Function & Memory API (预览)
- Vector API (第四次孵化)
JDK 20 (2023.03)
- 虚拟线程 (第二次预览)
- 结构化并发 (第二次孵化)
- Scoped Values (孵化) - 线程局部变量替代方案
- Record Patterns (第二次预览)
- Pattern Matching for switch (第四次预览)
- Foreign Function & Memory API (第二次预览)
- Vector API (第五次孵化)
JDK 21 (2023.09) - LTS ⭐
- 虚拟线程 (正式) 🎉 - 轻量级线程,大幅简化并发编程
- Record Patterns (正式)
- Pattern Matching for switch (正式)
- Sequenced Collections - 有序集合新接口
- String Templates (预览) - 字符串模板
STR."Hello \{name}" - Unnamed Patterns and Variables (预览) -
_占位符 - Unnamed Classes and Instance Main Methods (预览)
- 结构化并发 (预览)
- Scoped Values (预览)
- Foreign Function & Memory API (第三次预览)
- Vector API (第六次孵化)
- Generational ZGC
- 弃用 Windows 32位 x86 移植
JDK 22 (2024.03)
- Unnamed Variables & Patterns (正式) -
_占位符正式可用 - String Templates (第二次预览)
- Statements before super() (预览) - 构造函数中 super() 前可执行语句
- Foreign Function & Memory API (正式) 🎉
- Stream Gatherers (预览) - 自定义中间操作
- Class-File API (预览) - 解析和生成 class 文件
- Launch Multi-File Source-Code Programs
- 结构化并发 (第二次预览)
- Scoped Values (第二次预览)
- Vector API (第七次孵化)
- Region Pinning for G1
JDK 23 (2024.09)
- Primitive Types in Patterns (预览) - switch 支持原始类型
- Module Import Declarations (预览) -
import module java.base - Implicitly Declared Classes (第二次预览)
- Flexible Constructor Bodies (第二次预览)
- Stream Gatherers (第二次预览)
- Class-File API (第二次预览)
- 结构化并发 (第三次预览)
- Scoped Values (第三次预览)
- Vector API (第八次孵化)
- Markdown 文档注释
- ZGC 默认使用分代模式
JDK 24 (2025.03)
- Stream Gatherers (正式) 🎉
- Class-File API (正式) 🎉
- Primitive Types in Patterns (第二次预览)
- Module Import Declarations (第二次预览)
- Flexible Constructor Bodies (第三次预览)
- 结构化并发 (第四次预览)
- Scoped Values (第四次预览)
- 移除 String Templates ❌ - 已从预览中移除,将重新设计
- Quantum-Resistant 加密算法
- JIT 编译后台优化改进
二、语言特性详解
1. Lambda 表达式 (JDK 8)
Lambda 是 Java 函数式编程的基础,允许将函数作为参数传递。
// 传统匿名内部类
Runnable r1 = new Runnable() {
@Override
public void run() {
System.out.println("Hello");
}
};
// Lambda 表达式
Runnable r2 = () -> System.out.println("Hello");
// 带参数的 Lambda
Comparator comp = (s1, s2) -> s1.compareTo(s2);
// 方法引用 - 更简洁
Comparator comp2 = String::compareTo;
函数式接口:只有一个抽象方法的接口
@FunctionalInterface
public interface MyFunction {
R apply(T t);
}
// 常用内置函数式接口
Function len = String::length;
Predicate isEmpty = String::isEmpty;
Consumer print = System.out::println;
Supplier supplier = () -> "Hello";
BiFunction concat = String::concat;
2. Stream API (JDK 8+)
流式处理集合数据,支持函数式、链式操作。
List names = List.of("Alice", "Bob", "Charlie", "David");
// 基本操作
List result = names.stream()
.filter(n -> n.length() > 3) // 过滤
.map(String::toUpperCase) // 转换
.sorted() // 排序
.distinct() // 去重
.limit(10) // 限制数量
.skip(2) // 跳过
.collect(Collectors.toList()); // 收集结果
// 聚合操作
long count = names.stream().count();
Optional first = names.stream().findFirst();
boolean allMatch = names.stream().allMatch(n -> n.length() > 2);
String joined = names.stream().collect(Collectors.joining(", "));
// 分组
Map> byLength = names.stream()
.collect(Collectors.groupingBy(String::length));
// 并行流 - 多核处理
List parallelResult = names.parallelStream()
.filter(n -> n.length() > 3)
.collect(Collectors.toList());
// reduce 归约
int sum = List.of(1, 2, 3, 4, 5).stream()
.reduce(0, Integer::sum);
// flatMap - 扁平化
List> nested = List.of(List.of(1, 2), List.of(3, 4));
List flat = nested.stream()
.flatMap(List::stream)
.toList(); // [1, 2, 3, 4]
JDK 9 Stream 增强:
// takeWhile - 取满足条件的前缀
Stream.of(1, 2, 3, 4, 5, 1, 2)
.takeWhile(n -> n < 4)
.toList(); // [1, 2, 3]
// dropWhile - 丢弃满足条件的前缀
Stream.of(1, 2, 3, 4, 5, 1, 2)
.dropWhile(n -> n < 4)
.toList(); // [4, 5, 1, 2]
// ofNullable - 处理可能为 null 的值
Stream.ofNullable(null).count(); // 0
Stream.ofNullable("hi").count(); // 1
// iterate 带终止条件
Stream.iterate(1, n -> n < 100, n -> n * 2)
.toList(); // [1, 2, 4, 8, 16, 32, 64]
3. Optional (JDK 8+)
优雅处理可能为 null 的值,避免 NullPointerException。
// 创建 Optional
Optional empty = Optional.empty();
Optional of = Optional.of("Hello"); // 不能为 null
Optional nullable = Optional.ofNullable(null); // 可以为 null
// 基本操作
String value = optional.orElse("default");
String value2 = optional.orElseGet(() -> expensiveComputation());
String value3 = optional.orElseThrow(); // JDK 10+
String value4 = optional.orElseThrow(() -> new RuntimeException("Not found"));
// 条件操作
optional.ifPresent(System.out::println);
optional.ifPresentOrElse( // JDK 9+
System.out::println,
() -> System.out.println("Empty")
);
// 转换和过滤
Optional length = optional
.filter(s -> s.length() > 3)
.map(String::length)
.flatMap(this::findById);
// JDK 9: or() - 提供替代 Optional
Optional result = optional.or(() -> Optional.of("alternative"));
// JDK 9: stream() - 转为 Stream
List list = optional.stream().toList();
// 链式处理
String result = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(City::getName)
.orElse("Unknown");
4. 新日期时间 API (JDK 8)
java.time 包,不可变、线程安全。
// 日期
LocalDate date = LocalDate.now();
LocalDate date2 = LocalDate.of(2025, 1, 7);
LocalDate date3 = LocalDate.parse("2025-01-07");
// 时间
LocalTime time = LocalTime.now();
LocalTime time2 = LocalTime.of(14, 30, 0);
// 日期时间
LocalDateTime dateTime = LocalDateTime.now();
LocalDateTime dateTime2 = LocalDateTime.of(date, time);
// 带时区
ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
Instant instant = Instant.now(); // UTC 时间戳
// 时间间隔
Duration duration = Duration.between(time1, time2);
Period period = Period.between(date1, date2);
// 格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH🇲🇲ss");
String formatted = dateTime.format(formatter);
LocalDateTime parsed = LocalDateTime.parse("2025-01-07 14:30:00", formatter);
// 计算
LocalDate tomorrow = date.plusDays(1);
LocalDate lastMonth = date.minusMonths(1);
LocalDate firstDayOfMonth = date.withDayOfMonth(1);
LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
5. var 局部变量类型推断 (JDK 10)
编译器自动推断局部变量类型。
// 基本使用
var list = new ArrayList(); // ArrayList
var map = Map.of("key", "value"); // Map
var stream = list.stream(); // Stream
// for 循环
for (var item : list) {
System.out.println(item);
}
for (var i = 0; i < 10; i++) {
// ...
}
// try-with-resources
try (var reader = new BufferedReader(new FileReader("file.txt"))) {
var line = reader.readLine();
}
// Lambda 参数 (JDK 11)
BiFunction concat = (var a, var b) -> a + b;
// 可以加注解
Function upper = (@NonNull var s) -> s.toUpperCase();
// ⚠️ 不能使用的场景
var x; // 错误:没有初始化
var y = null; // 错误:无法推断类型
var z = () -> {}; // 错误:Lambda 需要目标类型
var arr = {1, 2, 3}; // 错误:数组初始化需要类型
// 字段和方法参数不能使用 var
class MyClass {
var field = 1; // 错误
void method(var param) {} // 错误
}
6. 文本块 Text Blocks (JDK 15)
多行字符串字面量,保留格式。
// 传统方式
String json = "{\n" +
" \"name\": \"John\",\n" +
" \"age\": 30\n" +
"}";
// 文本块
String json = """
{
"name": "John",
"age": 30
}
""";
// HTML
String html = """
<h1>Hello, World!</h1>
""";
// SQL
String sql = """
SELECT id, name, email
FROM users
WHERE status = 'active'
ORDER BY name
""";
// 转义序列
String s1 = """
line1
line2\
still line2
"""; // \结尾表示不换行
String s2 = """
col1\scol2\scol3
"""; // \s 表示空格
// 格式化
String formatted = """
Name: %s
Age: %d
""".formatted("John", 30);
7. Records 记录类 (JDK 16)
不可变数据载体,自动生成构造器、getter、equals、hashCode、toString。
// 定义 Record
public record Point(int x, int y) {}
// 等价于以下传统类
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() { return x; }
public int y() { return y; }
@Override
public boolean equals(Object o) { /* ... */ }
@Override
public int hashCode() { /* ... */ }
@Override
public String toString() { return "Point[x=" + x + ", y=" + y + "]"; }
}
// 使用
Point p = new Point(10, 20);
int x = p.x(); // 访问器方法,不是 getX()
System.out.println(p); // Point[x=10, y=20]
// 紧凑构造器 - 验证
public record Person(String name, int age) {
public Person { // 紧凑构造器,参数隐式
if (age < 0) throw new IllegalArgumentException("Age cannot be negative");
name = name.trim(); // 可以修改参数
}
}
// 自定义构造器
public record Point(int x, int y) {
public Point(int xy) {
this(xy, xy); // 必须调用规范构造器
}
}
// 静态方法和实例方法
public record Rectangle(Point topLeft, Point bottomRight) {
public static Rectangle of(int x1, int y1, int x2, int y2) {
return new Rectangle(new Point(x1, y1), new Point(x2, y2));
}
public int width() {
return bottomRight.x() - topLeft.x();
}
}
// 实现接口
public record NamedPoint(String name, int x, int y) implements Serializable {}
// 泛型 Record
public record Pair(T first, U second) {}
8. Sealed Classes 密封类 (JDK 17)
限制哪些类可以继承或实现。
// 密封类
public sealed class Shape
permits Circle, Rectangle, Triangle {
}
// 允许的子类必须是 final、sealed 或 non-sealed
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) { this.radius = radius; }
}
public sealed class Rectangle extends Shape
permits Square {
// Rectangle 也是密封的,只允许 Square 继承
}
public final class Square extends Rectangle {}
public non-sealed class Triangle extends Shape {
// non-sealed 允许任何类继承
}
// 密封接口
public sealed interface Vehicle
permits Car, Truck, Motorcycle {
}
public record Car(String model) implements Vehicle {}
public record Truck(int capacity) implements Vehicle {}
public final class Motorcycle implements Vehicle {}
// 与 Pattern Matching 结合使用
public double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Triangle t -> 0.5 * t.base() * t.height();
// 编译器知道所有可能的子类,无需 default
};
}
9. Pattern Matching 模式匹配
9.1 instanceof 模式匹配 (JDK 16)
// 传统方式
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 在整个 if 块中可用
}
// 否定模式
if (!(obj instanceof String s)) {
return;
}
// s 在这里可用(因为上面 return 了)
System.out.println(s.length());
9.2 Switch 表达式 (JDK 14)
// 传统 switch 语句
int numLetters;
switch (day) {
case MONDAY:
case FRIDAY:
case SUNDAY:
numLetters = 6;
break;
case TUESDAY:
numLetters = 7;
break;
// ...
default:
throw new IllegalStateException();
}
// Switch 表达式 - 箭头语法
int numLetters = switch (day) {
case MONDAY, FRIDAY, SUNDAY -> 6;
case TUESDAY -> 7;
case THURSDAY, SATURDAY -> 8;
case WEDNESDAY -> 9;
};
// yield 返回值(多语句块)
String result = switch (status) {
case 1 -> "One";
case 2 -> {
log("Processing two");
yield "Two";
}
default -> "Unknown";
};
9.3 Switch 模式匹配 (JDK 21)
// 类型模式
String describe(Object obj) {
return switch (obj) {
case Integer i -> "Integer: " + i;
case Long l -> "Long: " + l;
case Double d -> "Double: " + d;
case String s -> "String: " + s;
case null -> "Null";
default -> "Unknown: " + obj.getClass();
};
}
// 守卫条件 (when)
String categorize(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "Positive integer";
case Integer i when i < 0 -> "Negative integer";
case Integer i -> "Zero";
case String s when s.isEmpty() -> "Empty string";
case String s -> "String: " + s;
default -> "Other";
};
}
// Record 模式
record Point(int x, int y) {}
record Circle(Point center, int radius) {}
String describe(Object obj) {
return switch (obj) {
case Point(int x, int y) -> "Point at (" + x + ", " + y + ")";
case Circle(Point(int x, int y), int r) ->
"Circle at (" + x + ", " + y + ") with radius " + r;
default -> "Unknown";
};
}
// 嵌套解构
record Pair(T first, U second) {}
void process(Object obj) {
switch (obj) {
case Pair(String s, Integer i) ->
System.out.println("String-Integer pair: " + s + ", " + i);
case Pair(Pair(String a, String b), Integer i) ->
System.out.println("Nested: " + a + ", " + b + ", " + i);
default -> {}
}
}
9.4 Record Patterns (JDK 21)
record Point(int x, int y) {}
record Rectangle(Point topLeft, Point bottomRight) {}
// 解构 Record
void printPoint(Object obj) {
if (obj instanceof Point(int x, int y)) {
System.out.println("x = " + x + ", y = " + y);
}
}
// 嵌套解构
void printRectangle(Object obj) {
if (obj instanceof Rectangle(Point(int x1, int y1), Point(int x2, int y2))) {
System.out.println("From (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ")");
}
}
// 泛型 Record 解构
record Box(T value) {}
void unbox(Box box) {
if (box instanceof Box(String s)) {
System.out.println("Contains: " + s);
}
}
10. Unnamed Variables 未命名变量 (JDK 22)
使用 _ 表示不需要使用的变量。
// 忽略不需要的变量
try {
// ...
} catch (Exception _) { // 不使用异常变量
System.out.println("An error occurred");
}
// for-each 循环
int count = 0;
for (var _ : list) { // 只需要计数
count++;
}
// Lambda
map.forEach((_, value) -> System.out.println(value));
// 模式匹配中忽略部分
record Point(int x, int y) {}
if (obj instanceof Point(int x, _)) { // 只关心 x
System.out.println("x = " + x);
}
switch (obj) {
case Point(int x, _) when x > 0 -> System.out.println("Positive x");
case Point(_, int y) when y > 0 -> System.out.println("Positive y");
default -> {}
}
// try-with-resources
try (var _ = ScopedContext.open()) {
// 只需要资源在作用域内,不需要引用它
}
11. 集合工厂方法 (JDK 9)
创建不可变集合的便捷方法。
// List.of()
List list = List.of("a", "b", "c");
// list.add("d"); // 抛出 UnsupportedOperationException
// Set.of()
Set set = Set.of(1, 2, 3);
// Map.of() - 最多 10 个键值对
Map map = Map.of(
"one", 1,
"two", 2,
"three", 3
);
// Map.ofEntries() - 更多键值对
Map map2 = Map.ofEntries(
Map.entry("one", 1),
Map.entry("two", 2),
Map.entry("three", 3),
Map.entry("four", 4)
// ... 可以更多
);
// 复制为不可变集合 (JDK 10)
List immutableCopy = List.copyOf(mutableList);
Set immutableSet = Set.copyOf(mutableSet);
Map immutableMap = Map.copyOf(mutableMap);
// Collectors.toUnmodifiableList/Set/Map (JDK 10)
List result = stream.collect(Collectors.toUnmodifiableList());
// 直接 toList() (JDK 16)
List result = stream.toList(); // 返回不可变列表
12. Sequenced Collections (JDK 21)
为有序集合提供统一接口。
// 新接口层次
// SequencedCollection extends Collection
// SequencedSet extends Set, SequencedCollection
// SequencedMap extends Map
// 获取首尾元素
SequencedCollection seq = new LinkedHashSet<>();
seq.addFirst("first");
seq.addLast("last");
String first = seq.getFirst();
String last = seq.getLast();
seq.removeFirst();
seq.removeLast();
// 反转视图
SequencedCollection reversed = seq.reversed();
// SequencedMap
SequencedMap map = new LinkedHashMap<>();
map.putFirst("first", 1);
map.putLast("last", 99);
Map.Entry firstEntry = map.firstEntry();
Map.Entry lastEntry = map.lastEntry();
map.pollFirstEntry();
map.pollLastEntry();
SequencedMap reversedMap = map.reversed();
// 现有类自动实现
// List -> SequencedCollection
// LinkedHashSet, TreeSet -> SequencedSet
// LinkedHashMap, TreeMap -> SequencedMap
三、并发编程特性
13. 虚拟线程 Virtual Threads (JDK 21)
轻量级线程,解决"一请求一线程"模型的可扩展性问题。
// 创建虚拟线程
Thread vThread = Thread.ofVirtual().start(() -> {
System.out.println("Running in virtual thread");
});
// 带名称的虚拟线程
Thread.ofVirtual()
.name("my-virtual-thread")
.start(() -> doSomething());
// 虚拟线程工厂
ThreadFactory factory = Thread.ofVirtual().factory();
// 使用 Executors
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 每个任务一个虚拟线程
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
} // 自动等待所有任务完成并关闭
// 传统平台线程对比
Thread platformThread = Thread.ofPlatform()
.name("platform-thread")
.start(() -> doSomething());
// 检查是否是虚拟线程
boolean isVirtual = Thread.currentThread().isVirtual();
// 最佳实践
// ✅ 适合 I/O 密集型任务
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
List> futures = urls.stream()
.map(url -> executor.submit(() -> fetchUrl(url)))
.toList();
for (var future : futures) {
System.out.println(future.get());
}
}
// ⚠️ 注意事项
// 1. 不要池化虚拟线程(它们本身就是轻量的)
// 2. 避免在虚拟线程中使用 synchronized(会固定到平台线程)
// 3. 优先使用 ReentrantLock 替代 synchronized
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
// 临界区
} finally {
lock.unlock();
}
虚拟线程 vs 平台线程:
| 特性 | 平台线程 | 虚拟线程 |
|---|---|---|
| 创建成本 | 高(~1MB 栈空间) | 低(~几KB) |
| 数量限制 | 数千个 | 数百万个 |
| 调度 | OS 调度 | JVM 调度 |
| 阻塞代价 | 高(浪费 OS 线程) | 低(自动挂起) |
| 适用场景 | CPU 密集型 | I/O 密集型 |
14. 结构化并发 Structured Concurrency (JDK 21 预览)
将并发任务结构化,确保任务生命周期与代码块对齐。
// 结构化并发
Response handle() throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 并行执行多个任务
Supplier user = scope.fork(() -> findUser());
Supplier order = scope.fork(() -> fetchOrder());
scope.join(); // 等待所有任务完成
scope.throwIfFailed(); // 如果有任务失败则抛出异常
// 所有任务成功,获取结果
return new Response(user.get(), order.get());
}
}
// ShutdownOnSuccess - 任意一个成功就返回
T race(List> tasks) throws Exception {
try (var scope = new StructuredTaskScope.ShutdownOnSuccess()) {
for (var task : tasks) {
scope.fork(task);
}
scope.join();
return scope.result(); // 返回第一个成功的结果
}
}
// 自定义策略
class CollectingScope extends StructuredTaskScope {
private final Collection results = new ConcurrentLinkedQueue<>();
private final Collection errors = new ConcurrentLinkedQueue<>();
@Override
protected void handleComplete(Subtask subtask) {
switch (subtask.state()) {
case SUCCESS -> results.add(subtask.get());
case FAILED -> errors.add(subtask.exception());
case UNAVAILABLE -> {}
}
}
public Collection results() { return results; }
public Collection errors() { return errors; }
}
15. Scoped Values (JDK 21 预览)
线程局部变量的现代替代方案,适合虚拟线程。
// 定义 ScopedValue
private static final ScopedValue CURRENT_USER = ScopedValue.newInstance();
// 绑定值并在作用域内使用
void handleRequest(User user) {
ScopedValue.where(CURRENT_USER, user).run(() -> {
// 在这个作用域内,CURRENT_USER 绑定到 user
processRequest();
});
}
void processRequest() {
// 获取当前作用域的值
User user = CURRENT_USER.get();
// 或检查是否绑定
if (CURRENT_USER.isBound()) {
User user = CURRENT_USER.get();
}
// 带默认值
User user = CURRENT_USER.orElse(DEFAULT_USER);
}
// 嵌套绑定
ScopedValue.where(CURRENT_USER, user1).run(() -> {
System.out.println(CURRENT_USER.get()); // user1
ScopedValue.where(CURRENT_USER, user2).run(() -> {
System.out.println(CURRENT_USER.get()); // user2
});
System.out.println(CURRENT_USER.get()); // user1
});
// 与结构化并发结合
void handle() {
ScopedValue.where(CURRENT_USER, user).run(() -> {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
// 子任务自动继承 ScopedValue
scope.fork(() -> {
User u = CURRENT_USER.get(); // 可以访问
return processA(u);
});
scope.fork(() -> {
User u = CURRENT_USER.get(); // 可以访问
return processB(u);
});
scope.join();
}
});
}
ScopedValue vs ThreadLocal:
| 特性 | ThreadLocal | ScopedValue |
|---|---|---|
| 可变性 | 可变 | 不可变 |
| 生命周期 | 显式 remove | 自动作用域 |
| 继承 | InheritableThreadLocal | 自动继承(结构化并发) |
| 内存 | 可能泄漏 | 自动释放 |
| 虚拟线程 | 每个线程都复制 | 高效共享 |
四、API 和工具改进
16. HTTP Client (JDK 11)
现代化的 HTTP 客户端,支持 HTTP/2 和 WebSocket。
// 创建 HttpClient
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_2)
.connectTimeout(Duration.ofSeconds(10))
.followRedirects(HttpClient.Redirect.NORMAL)
.proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 8080)))
.authenticator(Authenticator.getDefault())
.build();
// 同步 GET 请求
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/data"))
.header("Accept", "application/json")
.GET()
.build();
HttpResponse response = client.send(request,
HttpResponse.BodyHandlers.ofString());
int status = response.statusCode();
String body = response.body();
HttpHeaders headers = response.headers();
// 异步请求
CompletableFuture> futureResponse =
client.sendAsync(request, HttpResponse.BodyHandlers.ofString());
futureResponse.thenAccept(resp -> {
System.out.println("Status: " + resp.statusCode());
System.out.println("Body: " + resp.body());
});
// POST 请求
HttpRequest postRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("""
{"name": "John", "email": "john@example.com"}
"""))
.build();
// 文件上传
HttpRequest uploadRequest = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/upload"))
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("file.txt")))
.build();
// 响应处理器
HttpResponse fileResponse = client.send(request,
HttpResponse.BodyHandlers.ofFile(Path.of("response.txt")));
HttpResponse streamResponse = client.send(request,
HttpResponse.BodyHandlers.ofInputStream());
HttpResponse> linesResponse = client.send(request,
HttpResponse.BodyHandlers.ofLines());
// 并发请求
List requests = urls.stream()
.map(url -> HttpRequest.newBuilder(URI.create(url)).build())
.toList();
List>> futures = requests.stream()
.map(req -> client.sendAsync(req, HttpResponse.BodyHandlers.ofString()))
.toList();
CompletableFuture.allOf(futures.toArray(CompletableFuture[]::new)).join();
17. String 新方法
// JDK 11
" hello ".strip(); // "hello" (Unicode 感知的 trim)
" hello ".stripLeading(); // "hello "
" hello ".stripTrailing();// " hello"
"".isBlank(); // true
" ".isBlank(); // true
"hello\nworld".lines(); // Stream: ["hello", "world"]
"ha".repeat(3); // "hahaha"
// JDK 12
"hello".indent(4); // " hello\n"
" hello".indent(-2); // "hello\n"
"hello".transform(s -> s.toUpperCase()); // "HELLO"
// JDK 15 (文本块相关)
"hello\nworld".stripIndent(); // 移除公共缩进
"hello\\nworld".translateEscapes(); // 处理转义: "hello\nworld"
// formatted (JDK 15)
"Name: %s, Age: %d".formatted("John", 30); // "Name: John, Age: 30"
18. Files 新方法
// JDK 11
// 读取整个文件为字符串
String content = Files.readString(Path.of("file.txt"));
String content = Files.readString(Path.of("file.txt"), StandardCharsets.UTF_8);
// 写入字符串到文件
Files.writeString(Path.of("file.txt"), "Hello, World!");
Files.writeString(Path.of("file.txt"), "Append",
StandardOpenOption.APPEND);
// JDK 12
// mismatch - 查找两个文件第一个不同的位置
long pos = Files.mismatch(path1, path2); // -1 表示完全相同
19. Process API (JDK 9+)
// 获取当前进程信息
ProcessHandle current = ProcessHandle.current();
long pid = current.pid();
ProcessHandle.Info info = current.info();
Optional command = info.command();
Optional arguments = info.arguments();
Optional startTime = info.startInstant();
Optional cpuDuration = info.totalCpuDuration();
// 获取所有进程
ProcessHandle.allProcesses()
.filter(p -> p.info().command().isPresent())
.forEach(p -> System.out.println(p.pid() + ": " + p.info().command().get()));
// 进程树
current.children(); // 直接子进程
current.descendants(); // 所有后代进程
current.parent(); // 父进程
// 等待进程结束
process.onExit().thenAccept(p -> {
System.out.println("Process " + p.pid() + " exited");
});
// 销毁进程
process.destroy(); // 正常终止
process.destroyForcibly(); // 强制终止
20. Foreign Function & Memory API (JDK 22)
访问本地代码和堆外内存的现代 API,替代 JNI。
// 内存分配
try (Arena arena = Arena.ofConfined()) {
// 分配 100 字节
MemorySegment segment = arena.allocate(100);
// 写入数据
segment.set(ValueLayout.JAVA_INT, 0, 42);
segment.set(ValueLayout.JAVA_LONG, 4, 123456789L);
// 读取数据
int value = segment.get(ValueLayout.JAVA_INT, 0);
// 分配数组
MemorySegment array = arena.allocate(ValueLayout.JAVA_INT, 10);
for (int i = 0; i < 10; i++) {
array.setAtIndex(ValueLayout.JAVA_INT, i, i * i);
}
} // 自动释放内存
// 调用本地函数
// 假设要调用 C 函数: size_t strlen(const char* str)
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle strlen = linker.downcallHandle(
stdlib.find("strlen").orElseThrow(),
FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)
);
try (Arena arena = Arena.ofConfined()) {
MemorySegment str = arena.allocateFrom("Hello");
long len = (long) strlen.invoke(str);
System.out.println("Length: " + len); // 5
}
// 内存映射文件
try (FileChannel channel = FileChannel.open(path, READ, WRITE);
Arena arena = Arena.ofConfined()) {
MemorySegment mapped = channel.map(READ_WRITE, 0, channel.size(), arena);
// 直接操作映射内存
int firstInt = mapped.get(ValueLayout.JAVA_INT, 0);
}
21. Stream Gatherers (JDK 24)
自定义 Stream 中间操作。
// 内置 Gatherers
// 窗口操作
Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowFixed(2))
.toList(); // [[1, 2], [3, 4], [5]]
Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowSliding(3))
.toList(); // [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
// fold - 有状态的归约
Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.fold(() -> 0, Integer::sum))
.toList(); // [1, 3, 6, 10, 15] - 运行总和
// scan - 类似 fold 但包含初始值
Stream.of(1, 2, 3)
.gather(Gatherers.scan(() -> 0, Integer::sum))
.toList(); // [0, 1, 3, 6]
// mapConcurrent - 并发映射
Stream.of(url1, url2, url3)
.gather(Gatherers.mapConcurrent(10, this::fetchUrl))
.toList();
// 自定义 Gatherer
Gatherer doubleOdds = Gatherer.of(
(state, element, downstream) -> {
if (element % 2 != 0) {
return downstream.push(element * 2);
}
return true;
}
);
Stream.of(1, 2, 3, 4, 5)
.gather(doubleOdds)
.toList(); // [2, 6, 10]
// 带状态的 Gatherer
Gatherer runningMax = Gatherer.ofSequential(
() -> new int[]{Integer.MIN_VALUE}, // 初始状态
(state, element, downstream) -> {
state[0] = Math.max(state[0], element);
return downstream.push(state[0]);
}
);
Stream.of(3, 1, 4, 1, 5, 9, 2, 6)
.gather(runningMax)
.toList(); // [3, 3, 4, 4, 5, 9, 9, 9]
五、垃圾收集器演进
22. G1 (Garbage First)
JDK 9 开始成为默认 GC。
# 启用 G1(JDK 9+ 默认)
-XX:+UseG1GC
# 设置期望的最大停顿时间
-XX:MaxGCPauseMillis=200
# 堆区域大小(1MB-32MB,2的幂)
-XX:G1HeapRegionSize=4m
# 并发 GC 线程数
-XX:ConcGCThreads=4
# 触发并发标记的堆占用阈值
-XX:InitiatingHeapOccupancyPercent=45
关键改进:
- JDK 10: 并行 Full GC
- JDK 12: 可中断 Mixed GC
- JDK 14: NUMA 感知
- JDK 22: Region Pinning(JNI 友好)
23. ZGC (Z Garbage Collector)
超低延迟 GC,停顿时间通常 < 1ms。
# 启用 ZGC
-XX:+UseZGC
# 启用分代 ZGC(JDK 21+,JDK 23 默认)
-XX:+UseZGC -XX:+ZGenerational
# 设置堆大小
-Xmx16g
# 并发 GC 线程数
-XX:ConcGCThreads=4
特点:
- 停顿时间不随堆大小增长(可达 TB 级堆)
- 并发压缩
- 彩色指针
- 加载屏障
- JDK 15 正式发布
- JDK 21 引入分代模式
- JDK 23 分代模式成为默认
24. Shenandoah GC
低停顿 GC,由 Red Hat 开发。
# 启用 Shenandoah
-XX:+UseShenandoahGC
# 设置堆大小
-Xmx16g
# GC 启发式策略
-XX:ShenandoahGCHeuristics=adaptive
特点:
- 并发压缩
- 与 ZGC 类似的低延迟目标
- JDK 15 正式发布
- 不在 Oracle JDK 中(在 OpenJDK 中)
六、其他重要改进
25. 接口私有方法 (JDK 9)
public interface MyInterface {
default void publicMethod() {
privateHelper();
}
private void privateHelper() {
// 私有方法实现
}
private static void privateStaticHelper() {
// 静态私有方法
}
}
26. try-with-resources 改进 (JDK 9)
// JDK 7 - 必须在 try 中声明
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
// ...
}
// JDK 9 - 可以使用 effectively final 变量
BufferedReader reader = new BufferedReader(new FileReader(file));
try (reader) { // reader 是 effectively final
// ...
}
// 多个资源
BufferedReader reader1 = new BufferedReader(new FileReader(file1));
BufferedReader reader2 = new BufferedReader(new FileReader(file2));
try (reader1; reader2) {
// ...
}
27. NullPointerException 增强 (JDK 14)
// 传统错误信息
a.b.c.d = 10;
// NullPointerException: null
// JDK 14+ 详细信息
// NullPointerException: Cannot read field "c" because "a.b" is null
// 启用(JDK 14 需要显式启用,JDK 15+ 默认)
// -XX:+ShowCodeDetailsInExceptionMessages
28. 模块系统 (JDK 9)
// module-info.java
module com.myapp {
// 依赖其他模块
requires java.sql;
requires transitive java.logging; // 传递依赖
// 导出包
exports com.myapp.api;
exports com.myapp.internal to com.myapp.plugin; // 限定导出
// 开放包供反射
opens com.myapp.model;
opens com.myapp.internal to com.fasterxml.jackson.databind;
// 使用服务
uses com.myapp.spi.Plugin;
// 提供服务实现
provides com.myapp.spi.Plugin with
com.myapp.impl.DefaultPlugin,
com.myapp.impl.AdvancedPlugin;
}
// 编译和运行
// javac -d out --module-source-path src $(find src -name "*.java")
// java --module-path out -m com.myapp/com.myapp.Main
29. JShell (JDK 9)
交互式 Java REPL。
$ jshell
jshell> int x = 10
x ==> 10
jshell> String greeting = "Hello"
greeting ==> "Hello"
jshell> greeting.toUpperCase()
$3 ==> "HELLO"
jshell> void sayHello(String name) {
...> System.out.println("Hello, " + name);
...> }
| created method sayHello(String)
jshell> sayHello("World")
Hello, World
jshell> /list
1 : int x = 10;
2 : String greeting = "Hello";
3 : greeting.toUpperCase()
4 : void sayHello(String name) { ... }
5 : sayHello("World")
jshell> /exit
30. jpackage 打包工具 (JDK 16)
创建平台特定的安装包。
# 创建应用镜像
jpackage --type app-image \
--name MyApp \
--input target/libs \
--main-jar myapp.jar \
--main-class com.myapp.Main
# 创建安装包
# Windows: exe, msi
jpackage --type msi --name MyApp ...
# macOS: dmg, pkg
jpackage --type dmg --name MyApp ...
# Linux: deb, rpm
jpackage --type deb --name MyApp ...
# 更多选项
jpackage \
--type msi \
--name "My Application" \
--app-version 1.0.0 \
--vendor "My Company" \
--description "My awesome application" \
--icon app.ico \
--input target/libs \
--main-jar myapp.jar \
--main-class com.myapp.Main \
--java-options "-Xmx512m" \
--win-menu \
--win-shortcut
七、总结
关键里程碑
| 版本 | 最重要特性 |
|---|---|
| JDK 8 | Lambda、Stream、Optional |
| JDK 9 | 模块系统 |
| JDK 10 | var 类型推断 |
| JDK 11 | HTTP Client、String 增强 |
| JDK 14 | Switch 表达式、NPE 增强 |
| JDK 15 | 文本块 |
| JDK 16 | Records、instanceof 模式匹配 |
| JDK 17 | Sealed Classes |
| JDK 21 | 虚拟线程、Pattern Matching for switch |
| JDK 22 | Foreign Function & Memory API |
| JDK 24 | Stream Gatherers、Class-File API |
版本演进时间线
JDK 8 (2014.03) ─── Lambda │ Stream │ Optional │ Date/Time API
│
JDK 9 (2017.09) ─── Module System │ JShell │ Collection Factories
│
JDK 10 (2018.03) ─── var (局部变量类型推断)
│
JDK 11 (2018.09) LTS ─── HTTP Client │ String 增强 │ ZGC (实验)
│
JDK 12 (2019.03) ─── Switch 表达式 (预览)
│
JDK 13 (2019.09) ─── 文本块 (预览)
│
JDK 14 (2020.03) ─── Switch 表达式 │ NPE 增强 │ Records (预览)
│
JDK 15 (2020.09) ─── Text Blocks │ Sealed Classes (预览) │ ZGC 正式
│
JDK 16 (2021.03) ─── Records │ instanceof Pattern │ jpackage
│
JDK 17 (2021.09) LTS ─── Sealed Classes │ Pattern Matching Switch (预览)
│
JDK 18 (2022.03) ─── 默认 UTF-8 │ 简单 Web 服务器
│
JDK 19 (2022.09) ─── 虚拟线程 (预览) │ 结构化并发 (孵化)
│
JDK 20 (2023.03) ─── 虚拟线程 (第二次预览) │ Scoped Values (孵化)
│
JDK 21 (2023.09) LTS ─── Virtual Threads │ Record Patterns │ Sequenced Collections
│
JDK 22 (2024.03) ─── Unnamed Variables │ FFM API │ Stream Gatherers (预览)
│
JDK 23 (2024.09) ─── 分代 ZGC 默认 │ Markdown 文档注释
│
JDK 24 (2025.03) ─── Stream Gatherers │ Class-File API │ Quantum-Resistant Crypto
LTS 版本建议
- 新项目: 推荐使用 JDK 21(最新 LTS,包含虚拟线程等重要特性)
- 保守升级: 可选择 JDK 17(稳定的 LTS 版本)
- 遗留系统: JDK 11 仍然是可靠选择
- 不建议: JDK 8 已经较老,建议尽快升级
文档最后更新: 2025-01-07

0 评论
评论