JDK 8
JDK 8 的核心变化是把函数式编程能力引入 Java,同时补齐日期时间、异步编程和常用基础 API。它也是后续版本演进的基线。
Lambda 与函数式接口
Lambda 可以把行为作为参数传递。函数式接口只能有一个抽象方法,可以使用 @FunctionalInterface 让编译器进行校验。
java
@FunctionalInterface
interface Converter<F, T> {
T convert(F value);
}
Converter<String, Integer> converter = Integer::valueOf;
int result = converter.convert("42");常用函数式接口包括 Predicate<T>、Function<T, R>、Consumer<T>、Supplier<T>、UnaryOperator<T> 和 BinaryOperator<T>。
接口方法
接口可以声明 default 方法和 static 方法,在不破坏已有实现类的前提下演进 API。
java
interface Named {
String name();
default String displayName() {
return name().toUpperCase();
}
static Named of(String name) {
return () -> name;
}
}Stream API
Stream 用声明式流水线处理数据,分为中间操作和终止操作。Stream 本身不存储数据,也不能重复消费。
java
List<String> names = users.stream()
.filter(User::isActive)
.map(User::getName)
.distinct()
.sorted()
.collect(Collectors.toList());Stream.toList() 到 JDK 16 才加入,因此 JDK 8 必须使用 Collector。
并行流使用公共 ForkJoinPool,不应看到 parallelStream() 就默认使用;需要结合数据规模、任务性质和线程池干扰评估。
Date and Time API
java.time 替代线程不安全且语义混乱的 Date、Calendar 和 SimpleDateFormat。
| 类型 | 用途 |
|---|---|
Instant | UTC 时间线上的时间点 |
LocalDate | 不带时区的日期 |
LocalDateTime | 不带时区的日期时间 |
ZonedDateTime | 带时区规则的日期时间 |
Duration | 基于秒和纳秒的时间量 |
Period | 基于年月日的日期量 |
CompletableFuture
CompletableFuture 支持异步任务编排、转换、组合和异常处理。
java
CompletableFuture<User> userFuture =
CompletableFuture.supplyAsync(() -> userService.find(id), executor);
CompletableFuture<List<Order>> orderFuture =
userFuture.thenApplyAsync(user -> orderService.findByUser(user.id()), executor);生产环境应显式传入业务线程池,避免所有任务争用公共 ForkJoinPool。
其他重要变化
| 特性 | 说明 |
|---|---|
Optional | 表达可能缺失的返回值,不建议作为实体字段或方法参数滥用 |
| 方法与构造器引用 | Type::method、object::method、Type::new |
| 重复注解 | 使用 @Repeatable 在同一声明上重复应用注解 |
| 类型注解 | 注解可以出现在类型使用位置,便于静态分析 |
| Base64 API | java.util.Base64 提供 Basic、URL、MIME 编解码 |
| Map 增强 | computeIfAbsent、merge、forEach 等默认方法 |
| 并发累加器 | LongAdder、LongAccumulator 降低高竞争计数开销 |
| 元空间 | HotSpot 使用本地内存中的 Metaspace 取代永久代 |
| Nashorn | 引入 JavaScript 引擎,后来在 JDK 15 中移除 |
架构与迁移关注
- Lambda 捕获的局部变量必须是 final 或 effectively final。
- Stream 的延迟执行和副作用会增加调试难度,业务流水线应保持无状态。
Optional.get()可能抛异常,应优先使用orElseThrow、map、flatMap等组合方法。- JDK 8 引入 Metaspace 后,类加载泄漏仍然存在,只是监控参数从永久代切换到了 Metaspace。