Java 从 Java 8 到 Java 21 经历了巨大的演进,本指南将从基础到高级,全面系统地对比这两个长期支持版本(LTS)的主要差异,帮助开发者深入理解并掌握现代 Java 开发的核心技术。
第一部分:基础特性对比
1. 语言特性增强
Java 8 引入的核心特性
Lambda 表达式
// Java 8 之前
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.compareTo(b);
}
});
// Java 8 Lambda
Collections.sort(list, (a, b) -> a.compareTo(b));
Lambda 表达式是 Java 8 最重大的改进之一,它使得 Java 具备了函数式编程的能力。Lambda 表达式由三部分组成:
- 参数列表:(a, b)
- 箭头符号:->
- 表达式或语句块:a.compareTo(b)
方法引用
// 静态方法引用
list.forEach(System.out::println);
// 实例方法引用
list.forEach(String::toUpperCase);
// 构造方法引用
Supplier<List<String>> listSupplier = ArrayList::new;
方法引用进一步简化了 Lambda 表达式的写法,使代码更加简洁易读。
Stream API
List<String> result = list.stream()
.filter(s -> s.startsWith("A"))
.map(String::toLowerCase)
.sorted()
.collect(Collectors.toList());
Stream API 提供了对集合数据进行函数式操作的能力,主要特点包括:
- 惰性求值:中间操作不会立即执行
- 管道化:可以串联多个操作
- 内部迭代:不需要显式编写循环语句
Java 21 新增/改进的特性
记录类 (Record)
public record Person(String name, int age, String address) {
// 自动生成:
// 1. 全参数构造方法
// 2. 访问器方法 name(), age(), address()
// 3. equals(), hashCode(), toString()
}
// 使用示例
Person person = new Person("Alice", 30, "New York");
System.out.println(person.name()); // 访问字段
记录类的主要特点:
- 不可变性:所有字段默认是 final 的
- 透明数据载体:自动生成标准方法
- 简洁语法:大幅减少样板代码
模式匹配 (Pattern Matching)
// instanceof 模式匹配
if (obj instanceof String s && s.length() > 5) {
System.out.println("长字符串: " + s);
}
// switch 模式匹配
String formatted = switch (obj) {
case Integer i -> String.format("整数: %d", i);
case Double d -> String.format("浮点数: %f", d);
case String s -> String.format("字符串: %s", s);
case null -> "null";
default -> obj.toString();
};
模式匹配的优势:
- 减少类型检查和强制转换的样板代码
- 使代码更加直观和安全
- 结合记录类使用时特别强大
文本块 (Text Blocks)
// Java 8 方式
String html = "<html>\n" +
" <body>\n" +
" <p>Hello, world!</p>\n" +
" </body>\n" +
"</html>";
// Java 21 文本块
String html = """
<html>
<body>
<p>Hello, world!</p>
</body>
</html>
""";
文本块特性:
- 保留原始格式,包括换行和缩进
- 自动处理行终止符
- 支持转义序列
- 特别适合HTML、SQL、JSON等多行字符串
2. 集合框架改进
Java 8 集合改进
- 新增 Collection.removeIf(), List.replaceAll(), List.sort() 等默认方法
- Map 接口新增 compute(), merge(), getOrDefault() 等方法
- ConcurrentHashMap 性能优化,新增流式操作方法
Java 21 集合改进
- 序列化集合 (Sequenced Collections)
List<Integer> list = new ArrayList<>();
list.addFirst(1); // 头部插入
list.addLast(2); // 尾部插入
int first = list.getFirst(); // 获取第一个元素
int last = list.getLast(); // 获取最后一个元素
- 不可变集合工厂方法
List<String> immutableList = List.of("a", "b", "c");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, Integer> immutableMap = Map.of("a", 1, "b", 2);
- 集合与流之间的转换更便捷
// 直接通过集合创建流
List<String> list = ...;
Stream<String> stream = list.stream();
// 流收集为不可变集合
List<String> newList = stream.collect(Collectors.toUnmodifiableList());
3. 日期时间 API
Java 8 引入的 java.time 包
// 本地日期时间
LocalDate today = LocalDate.now();
LocalTime now = LocalTime.now();
LocalDateTime current = LocalDateTime.now();
// 时区日期时间
ZonedDateTime zoned = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
// 时间差计算
Duration duration = Duration.between(startTime, endTime);
Period period = Period.between(startDate, endDate);
// 格式化和解析
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted = current.format(formatter);
LocalDateTime parsed = LocalDateTime.parse("2025-08-18 14:30:00", formatter);
Java 21 日期时间改进
- 新增 DateTimeFormatterBuilder.appendDayPeriodText()
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd ")
.appendDayPeriodText()
.toFormatter();
String formatted = LocalDateTime.now().format(formatter); // "2025-08-18 下午"
- 增强的时区支持
// 获取所有可用时区
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
// 时区转换
ZonedDateTime newYorkTime = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime shanghaiTime = newYorkTime.withZoneSameInstant(ZoneId.of("Asia/Shanghai"));
第二部分:中级特性对比
1. 并发编程改进
Java 8 并发特性
- CompletableFuture 引入
CompletableFuture.supplyAsync(() -> fetchData())
.thenApply(data -> processData(data))
.thenAccept(result -> storeResult(result))
.exceptionally(ex -> handleError(ex));
- 新增 StampedLock 乐观读锁
StampedLock lock = new StampedLock();
long stamp = lock.tryOptimisticRead();
// 读操作
if (!lock.validate(stamp)) {
stamp = lock.readLock();
try {
// 重新读操作
} finally {
lock.unlockRead(stamp);
}
}
- 并发累加器 (LongAdder, DoubleAdder)
LongAdder adder = new LongAdder();
IntStream.range(0, 100).parallel().forEach(i -> adder.add(i));
long sum = adder.sum();
Java 21 虚拟线程 (Virtual Threads)
// 创建虚拟线程
Thread.startVirtualThread(() -> {
System.out.println("Running in virtual thread");
});
// 使用虚拟线程执行器
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i -> {
executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(1));
return i;
});
});
}
// 结构化并发
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser(userId));
Future<Integer> order = scope.fork(() -> fetchOrder(orderId));
scope.join();
scope.throwIfFailed();
return new Response(user.resultNow(), order.resultNow());
}
虚拟线程的关键优势:
- 轻量级:每个虚拟线程仅需约1KB内存
- 高吞吐:可创建数百万个虚拟线程
- 简单编程模型:保持同步代码风格
- 自动调度:阻塞操作不会占用OS线程
2. Optional 类的改进
Java 8 Optional
Optional<String> optional = Optional.ofNullable(getString());
// 存在时执行操作
optional.ifPresent(System.out::println);
// 不存在时提供默认值
String value = optional.orElse("default");
// 链式操作
optional.map(String::toUpperCase)
.filter(s -> s.length() > 5)
.orElseThrow();
Java 21 Optional 增强
// ifPresentOrElse
optional.ifPresentOrElse(
value -> System.out.println("Found: " + value),
() -> System.out.println("Not found"))
);
// or
Optional<String> fallback = optional.or(() -> Optional.of("fallback"));
// stream
Stream<String> stream = optional.stream();
3. 接口的演变
Java 8 接口
public interface MyInterface {
// 抽象方法
void abstractMethod();
// 默认方法
default void defaultMethod() {
System.out.println("Default implementation");
}
// 静态方法
static void staticMethod() {
System.out.println("Static method");
}
}
Java 21 接口
public interface MyInterface {
// 私有方法
private void privateMethod() {
System.out.println("Private method");
}
// 默认方法可以调用私有方法
default void defaultMethod() {
privateMethod();
System.out.println("Default implementation");
}
// 密封接口
sealed interface SealedInterface permits Implementation1, Implementation2 {}
}
第三部分:高级特性对比
1. 模块系统 (Java 9+)
Java 21 模块化
// module-info.java
module com.example.myapp {
requires java.base;
requires java.sql;
requires transitive com.example.utils;
exports com.example.myapp.api;
opens com.example.myapp.internal to com.example.test;
}
模块化的关键概念:
- 强封装:明确声明导出和开放的包
- 显式依赖:必须声明所有依赖
- 服务加载:通过 provides 和 uses 声明服务
- 自定义运行时:使用 jlink 创建精简运行时
2. 垃圾回收器改进
Java 8 垃圾回收
- 并行收集器 (Parallel GC):高吞吐量,适合批处理应用
- CMS (Concurrent Mark-Sweep):低延迟,但会产生内存碎片
- G1 (Garbage-First):需手动启用 (-XX:+UseG1GC)
Java 21 垃圾回收
- G1 作为默认收集器
- ZGC (Z Garbage Collector):亚毫秒级停顿
java -XX:+UseZGC -Xmx4g -jar myapp.jar
- Shenandoah:低停顿时间的并发收集器
java -XX:+UseShenandoahGC -Xmx4g -jar myapp.jar
3. 性能优化
Java 21 性能改进
- 启动时间优化:类数据共享 (CDS)
# 生成共享归档
java -Xshare:dump
# 使用共享归档
java -Xshare:on -jar myapp.jar
- AOT 编译 (GraalVM Native Image)
native-image -jar myapp.jar
- 向量 API (SIMD 指令)
var a = FloatVector.fromArray(FloatVector.SPECIES_256, arrayA, 0);
var b = FloatVector.fromArray(FloatVector.SPECIES_256, arrayB, 0);
var c = a.mul(b).add(a);
c.intoArray(result, 0);
4. 新API和工具
Java 21 新API
- HTTP Client API
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://example.com/api"))
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString("{\"key\":\"value\"}"))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
- 进程 API 增强
ProcessHandle current = ProcessHandle.current();
System.out.println("PID: " + current.pid());
System.out.println("Command: " + current.info().command().orElse("unknown"));
ProcessHandle.allProcesses()
.filter(p -> p.info().user().equals("alice"))
.forEach(p -> System.out.println(p.pid()));