本文整理了 Java 8 至 Java 24 各版本的新特性,内容包括每个版本的新增功能分类(如语法增强、性能优化、工具支持等)、详细的代码示例,并结合官方文档资料,分析每项特性的应用场景及优缺点。
Java 8 发布于 2014 年,此后 Java 进入快速迭代模式,每半年发布一个新版本。一路走来,Java 8 到 Java 24 带来了大量重要的新特性。下面将按版本逐一梳理各主要特性,并按“语言特性”“核心库”“性能优化与JVM”“工具与其他”等分类说明,每个特性附有示例代码和应用场景说明。
参考资料:

Java 8 新特性
发行时间: 2014 年 3 月
语言特性
- Lambda表达式与函数式接口:
Java 8 引入了 Lambda 表达式,使我们能够将匿名函数作为一等公民传递和使用。例如,可以使用Comparator<String> cmp = (a, b) -> a.length() - b.length();来实现字符串长度比较。这依赖于 函数式接口(只含单一抽象方法的接口),如 Comparator 或自定义接口,Lambda 会被推断成该接口的实现。有了 Lambda,代码变得更加简洁,可读性提高,尤其适用于集合的过滤、映射等操作。
// 示例:使用 Lambda 表达式对列表进行过滤和映射
List<String> list = Arrays.asList("GET","ALICE", "BOB", "ANN");
list.forEach(item -> System.out.println(item));
List<String> filtered = names.stream()
.filter(s -> s.startsWith("A"))
.map(s -> s.toUpperCase())
.collect(Collectors.toList());
System.out.println(filtered); // 输出: [ALICE, ANN]
-
方法引用:
除了 Lambda,Java 8 还支持 方法引用,可以用Class::method简洁地引用已有方法或构造器。例如,names.forEach(System.out::println)会打印列表中每个元素,相当于对每个元素执行System.out.println。方法引用与 Lambda 一样,也必须对应一个函数式接口目标类型。 -
接口默认方法和静态方法:
接口现在可以包含带实现的 默认方法(default方法)和 静态方法。这使得在不破坏已有实现类的前提下向接口添加新方法成为可能。默认方法可被实现类继承或重写;静态方法则只能通过接口名调用,不能被子类重写。
例如:
interface MyInterface {
static void staticMethod() {
System.out.println("接口静态方法");
}
default void defaultMethod() {
System.out.println("接口默认方法");
}
void abstractMethod();
}
class MyClass implements MyInterface {
@Override
public void abstractMethod() {
}
// 未重写 defaultMethod(),将继承接口的默认实现
}
MyInterface.staticMethod(); // 调用接口静态方法
new MyClass().defaultMethod(); // 调用接口默认方法,实现类未重写则执行接口中的实现
应用场景:
默认方法解决了接口演化的问题,比如 Java 8 为 Collection 接口添加了 stream() 默认方法,从而所有实现类无需修改就自动拥有流操作能力。静态方法则方便在接口中组织工具函数。
- 重复注解(Repeatable Annotation):
允许在同一声明或类型上多次应用同一个注解类型。Java 8 引入了@Repeatable元注解,通过定义“容器注解”类型来实现重复注解支持。应用场景如定义多个过滤器、多个权限注解等,使代码更直观。
例如:
@Schedule(day="Mon"), @Schedule(day="Tue")
void scheduledTask() {
... }
- 类型注解:
Java 8 扩展了注解使用的场景,注解现在可以加在任何类型使用处(Type Use),如泛型类型参数、强制转换、实现声明等。结合 JSR 308,可用于开发更强的类型检查工具(如空指针分析)。
核心库新特性
- Stream API:
Java 8 的Stream API为集合批量操作提供了声明式、链式的语法。开发者可以使用类似 SQL 风格的操作(filter, map, reduce等)来处理数据流。Stream的操作分为中间操作(惰性求值)和终止操作(触发计算)。
例如:
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 1) // 筛选奇数
.mapToInt(n -> n * n) // 平方映射
.sum(); // 终止操作求和
System.out.println(sum); // 输出: 35(1^2 + 3^2 + 5^2)
应用场景:
Stream API 大大简化了集合的复杂操作,避免了繁琐的迭代和临时集合管理。例如,可以轻松进行过滤、汇总统计、分组分区等操作。缺点是初学者需要学习 Lambda 表达式和流式思维,但一旦掌握,能编写出高可读性的流水线处理代码。
- Optional 类:
引入了java.util.Optional<T>,用于优雅地表示“可能为空”的值。Optional 提供了诸如isPresent(), ifPresent(), orElse()等方法,可以替代显式的空检查,减少空指针异常风险。
例如:
public Optional<User> findUser(String name) {
User result = ... // 查找用户
return Optional.ofNullable(result);
}
// 使用Optional避免显式null判断
findUser("Alice").ifPresent(user -> System.out.println(user.getId()));
User user = findUser("Bob").orElse(new User("Bob")); // 未找到则返回默认User
应用场景:
Optional 常用于方法返回值,表示“可能没有结果”。这比返回 null 更具语义,也迫使调用方处理不存在的情况。需要注意不要滥用在域对象上,Optional设计主要用于返回值,而非序列化或字段类型。
- 全新的日期时间 API:
Java 8 推出了java.time包(JSR 310),提供了不变且线程安全的日期时间类,包括LocalDate, LocalTime, LocalDateTime, ZonedDateTime等,以及用于周期和持续时间的Period, Duration。新的 API 改进了旧版java.util.Date和Calendar的诸多问题,提供了更加自然的时间操作接口。
例如:
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1990, Month.APRIL, 1);
Period period = Period.between(birthday, today);
System.out.printf("年龄: %d 年 %d 月 %d 日%n",
period.getYears(), period.getMonths(), period.getDays());
应用场景:
新日期API提供了清晰的方法来操作日期时间,支持时区、夏令时、安全不变。此外还提供了格式化和解析(DateTimeFormatter),大幅简化日期处理,避免了旧 API 各种不一致和缺陷。
-
并发增强(CompletableFuture 等):
Java 8 在并发库方面增加了CompletableFuture,支持以链式回调的方式处理异步结果,实现了Promise模式。例如可以组合多个异步计算、设置依赖和异常处理。此外,新增的并发工具包括并行数组排序(Arrays.parallelSort)、并发Accumulator、Adder等,改进了并行计算性能。 -
其它常用库改进:
例如Map.computeIfAbsent等函数式风格的方法,方便地对 Map 执行条件更新;Base64 编码解码器(java.util.Base64)也在 Java 8 加入成为标准库。
JVM 与性能优化
-
永久代移除:
Java 8 移除了 HotSpot VM 的永久代(PermGen),取而代之的是 元空间(Metaspace)。元空间在本地内存中分配且按需增长,大幅减少了因固定永久代空间不足导致的OutOfMemoryError情况,提高了内存管理的灵活性。开发者在升级时需要注意移除了永久代相关的 JVM 参数(如-XX:PermSize)。 -
垃圾回收优化:
Java 8 中虽然默认垃圾回收器仍是 Parallel GC,但引入了一些改进。例如引入串行/并行 Full GC 等优化;此外为 G1 垃圾收集器(实验性)打下基础。虽然 G1 直到 Java 9 才成为默认 GC,但在 Java 8 已可通过 -XX:+UseG1GC 使用,其目标是低停顿,更适合大堆内存应用。 -
HashMap 性能改进:
为了应对哈希碰撞,Java 8 改进了HashMap和ConcurrentHashMap的实现。当桶中链表长度超过阈值时,将链表转换为 红黑树 存储,从平均 O(n) 查找降为 O(log n)。这显著改善了哈希冲突严重时的性能**(优点),代价是结构更复杂(可能略增插入删除成本)**。但总体而言,这让HashMap在最坏情况下性能更可控。
工具和其他
-
Nashorn JavaScript 引擎:
Java 8 内置了全新的 JavaScript 引擎 Nashorn,替代了原有的 Rhino 引擎。Nashorn 利用 InvokeDynamic 提高了 JS 运行性能,可通过jjs命令运行 .js 脚本,也能在Java程序中使用ScriptEngine执行JS代码。在需要在 JVM 中嵌入脚本、实现动态逻辑的场景下,Nashorn 提供了更高性能和ES5兼容性。不过需要注意 Nashorn 在后续 Java 15 已被移除,建议长期方案还是GraalVM多语言支持。 -
增强的注解处理和反射:
Java 8 对反射和注解处理也有一些改进,如引入Parameter类来支持获取方法参数名(需加-parameters编译),以及AnnotatedElement接口新增方法直接获取重复注解等。这些增强使框架开发者更方便地获取运行时信息,构建更丰富的注解驱动逻辑。
总结:
Java 8 是一个里程碑版本,引入的 Lambda 和 Stream 等特性使Java正式进入函数式编程时代。默认方法等特性改善了接口演进能力。核心库的加强和全新时间API填补了多年痛点。在性能上,永久代的移除和集合优化提升了稳定性。Java 8 的诸多新功能为之后的Java版本奠定了基础,也是目前许多项目仍在使用的版本。
Java 9 新特性
发行时间: 2017 年 9 月
语言和语法增强
- 模块化系统(Project Jigsaw):
Java 9 最重要的变化是引入模块化系统。JDK 本身被重组为约 94 个模块,允许按需组合所需模块来构建定制的 Java 运行时(可使用下面提到的 jlink 工具)。开发者可以通过创建模块描述符module-info.java将应用拆分为模块。模块定义了所包含的包以及导出的内容和所需依赖,
例如:
// module-info.java 示例
module com.example.app {
requires com.example.utils; // 声明依赖模块
exports com.example.app.api; // 导出包供其他模块使用
}
模块系统解决了 classpath 下包命名冲突和封装不严的问题,实现强封装。只有模块导出的包才能被外部访问,未导出的内部实现包将被严格封装。这样提高了代码的可维护性和安全性。应用场景: 大型应用可以通过模块划分更好地管理依赖关系,同时在部署时使用 jlink 剔除无关模块减小体积。不过模块化也带来了学习曲线,且现有项目迁移需要调整访问限制(可以通过 --add-exports 等选项做兼容)。
-
接口私有方法:
除了 Java 8 的接口默认方法外,Java 9 支持接口定义 私有方法 来给多个默认方法复用业务逻辑。这提高了接口内部实现的封装性,避免默认方法之间代码重复。私有接口方法只能在接口内部被默认或静态方法调用,不会暴露给实现类。 -
try-with-resources 改进:
try-with-resources语法在 Java 9 更加方便。现在如果已有实现AutoCloseable的资源对象(final或 effectively final),可以直接在 try 语句中使用该变量,而不必再次声明。
例如:
// Java 8 及之前需要在 try 内新声明
try (BufferedReader br = Files.newBufferedReader(path)) {
... }
// Java 9 可以在 try 中直接使用已有的变量 br
BufferedReader br = Files.newBufferedReader(path);
try (br) {
// 使用 br 读取...
}
这减少了不必要的代码臃肿,让语法更简洁。
核心库增强
- 集合工厂方法:
Java 9 为集合接口添加了方便创建不可变集合的静态工厂方法。例如:List.of(1,2,3), Set.of("a","b"), Map.of("key1","val1","key2","val2")等,可以快捷地创建包含固定元素的集合。这些集合是不可修改的(修改会抛异常)。相比手动创建集合然后Collections.unmodifiableX,新方法更直观高效。
应用场景: 用于快速创建常量集合、简化测试用例数据准备等。
- Stream API 改进:
Java 9 为 Stream 增加了一些实用的新方法,如takeWhile, dropWhile 和 ofNullable等。其中 takeWhile(predicate) 会从 Stream 开头起连续获取满足条件的元素,直到遇到不满足条件者停止;dropWhile(predicate)则丢弃开头连续满足条件的元素。还有Stream.iterate支持提供断言来结束迭代。例如:
Stream.of(1,2,3,4,5).takeWhile(n -> n < 4) // 得到 [1,2,3]
Stream.of(1,2,3,4,5).dropWhile(n -> n < 4) // 得到 [4,5]
Stream.iterate(1, x -> x+1).takeWhile(x -> x<=5).forEach(System.out::println);
此外,Optional 也增加了 ifPresentOrElse, or 等方法,提高 Optional 的易用性。这些改进让流操作和 Optional 更加完备,减少手动处理。
- 进程 API:
新增 ProcessHandle 接口,提供了更现代的进程管理 API。通过 ProcessHandle.current() 可以获取当前进程信息,包括 PID 等;还能列出现有进程,观察进程树关系,设置监听等。相比以前只能通过 Runtime.getRuntime().exec() 启动进程、基本无反馈,新的 API 丰富了进程交互能力。例如:
ProcessHandle self = ProcessHandle.current();
long pid = self.pid();
self.info().


1094

被折叠的 条评论
为什么被折叠?



