Java 17 是一个非常重要的版本,它是自 Java 11 以来的第二个长期支持(LTS)版本,由 Oracle 提供至少到 2029 年的免费安全更新。它不仅包含了自 Java 12 到 Java 17 六个版本的所有预览和 incubator 特性的最终版本,还带来了许多性能、稳定性和安全性的提升。
以下是 Java 17 中最值得关注和最实用的特性,我将它们分为几类以便理解:
这些特性极大地提升了代码的简洁性和可读性,是开发者最能直接感受到的变化。
解决的问题:传统上,创建一个只用来承载数据的类(如 DTO、VO)需要编写大量模板代码:private
字段、public
getter、equals()
、hashCode()
和 toString()
。
Java 17 的解决方案:使用 record
关键字,编译器会自动生成所有这些代码。
示例代码:
// Java 17 之前
class PointOld {
private final int x;
private final int y;
public PointOld(int x, int y) { this.x = x; this.y = y; }
public int getX() { return x; }
public int getY() { return y; }
// 需要手动或通过 IDE 生成 equals, hashCode, toString
@Override public boolean equals(Object o) { /* ... */ }
@Override public int hashCode() { /* ... */ }
@Override public String toString() { /* ... */ }
}
// Java 17
public record Point(int x, int y) {}
// 使用起来和普通类一样
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 2);
System.out.println(p1.x()); // 自动生成的访问器方法
System.out.println(p1.equals(p2)); // true
System.out.println(p1); // Point[x=1, y=2]
好处:代码量锐减,意图更清晰,减少了出错的可能性。
解决的问题:在设计 API 时,有时希望某个类的继承关系是封闭的,即只有预先指定的类才能继承它,防止外部用户随意扩展。
Java 17 的解决方案:使用 sealed
关键字,并通过 permits
指定允许继承的子类。子类必须是 final
、sealed
或 non-sealed
。
示例代码:
// Shape 类只允许 Circle 和 Rectangle 继承
public sealed class Shape permits Circle, Rectangle {
public abstract double area();
}
// 子类必须是 final, sealed, 或 non-sealed
public final class Circle extends Shape {
private final double radius;
public Circle(double radius) { this.radius = radius; }
@Override public double area() { return Math.PI * radius * radius; }
}
// Rectangle 允许进一步被扩展
public non-sealed class Rectangle extends Shape {
private final double length;
private final double width;
public Rectangle(double length, double width) { this.length = length; this.width = width; }
@Override public double area() { return length * width; }
}
// 如果尝试创建一个未被 permits 的子类,将无法通过编译
// class Triangle extends Shape {} // 编译错误!
好处:增强了 API 的健壮性和可维护性,让类的层次结构更加可控。
解决的问题:在 if
或 else if
语句中,经常需要先使用 instanceof
判断对象类型,然后再进行强制类型转换。
Java 17 的解决方案:instanceof
可以直接将对象转换为目标类型的变量。
示例代码:
// Java 17 之前
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.length());
}
// Java 17
if (obj instanceof String s) {
// 在这里 s 已经是 String 类型,可以直接使用
System.out.println(s.length());
}
// 还可以和其他条件结合
if (obj instanceof String s && s.length() > 5) {
System.out.println("Long string: " + s);
}
好处:减少了代码行数,避免了重复的类型转换,代码更流畅。
这些特性为日常开发提供了更便捷的工具。
解决的问题:旧的 Random
类在高并发下性能不佳,且可选择的算法有限。
Java 17 的解决方案:引入了全新的 java.util.random
包,提供了更现代、更灵活的随机数生成器(RNG)接口和实现。
示例代码:
// 创建一个高性能的 LXM 算法随机数生成器
RandomGenerator rng = RandomGeneratorFactory.of("L32X64MixRandom").create();
// 生成不同类型的随机数
int intVal = rng.nextInt(100);
double doubleVal = rng.nextDouble(0.0, 1.0);
boolean boolVal = rng.nextBoolean();
// 支持流式生成
rng.ints(5, 0, 10).forEach(System.out::println);
好处:提供了多种算法选择(如 Xoshiro256PlusPlus
, L64X128MixRandom
),性能更好,支持流式 API,并且易于替换算法实现。
解决的问题:旧的 AWT/Swing 在 macOS 上的渲染性能和外观体验不佳。
Java 17 的解决方案:默认启用了基于 Apple Metal API 的新渲染管道。
好处:对于 macOS 用户来说,Java 桌面应用的性能、响应速度和视觉效果都有了显著提升。
这些特性虽然不直接体现在代码语法上,但对系统的整体表现至关重要。
解决的问题:Applet 技术早已被所有主流浏览器淘汰,维护它没有意义。
Java 17 的解决方案:正式将 java.applet
包标记为废弃,并计划在未来版本中移除。
好处:清理了过时的 API,让 JDK 更加现代化和轻量化。
解决的问题:长期以来,一些第三方库为了追求性能或实现特定功能,会反射访问 JDK 的内部 API。这给 JDK 的升级和维护带来了巨大挑战。
Java 17 的解决方案:默认情况下,JDK 的内部模块不再对外部代码开放深度反射访问。
好处:大大提高了 JDK 自身的安全性和稳定性,也促使库的开发者使用标准的公共 API,使整个生态系统更加健康。
总而言之,Java 17 是一个集大成的 LTS 版本。它不仅通过 Records、Sealed Classes 和 Pattern Matching 等特性让 Java 代码变得更现代、更简洁,还在性能、安全和平台兼容性方面做了大量优化。对于任何考虑升级或启动新项目的团队来说,从 Java 8 或 11 升级到 Java 17 都是一个非常值得且回报丰厚的选择。它也是学习后续版本(如 Java 21)新特性的坚实基础。