JDK 17(Java SE 17)是 2021 年 9 月发布的长期支持(LTS)版本,汇总了 JDK 11 到 JDK 17 之间的多项重要更新,在语言特性、性能、安全性和兼容性上均有显著提升。以下是 JDK 17 的主要新特性及重要特性的代码示例:
一、主要新特性列表
- 密封类(Sealed Classes):限制类的继承关系,仅允许指定的子类继承
- 模式匹配的
instanceof(Pattern Matching forinstanceof):简化类型判断与转换,减少冗余代码 - 增强的
switch表达式(Enhancedswitch):支持箭头语法、yield返回值,且可匹配模式(如类型模式) - 记录类(Records):简化不可变数据载体类的定义(JDK 16 正式引入,JDK 17 中稳定)
- 外部函数与内存 API(Foreign Function & Memory API):预览特性,提供安全高效的本地代码调用和内存访问(替代 JNI)
- 向量 API(Vector API):第二次孵化,支持硬件加速的向量计算,提升数值处理性能
- 移除实验性的 AOT 和 JIT 编译器:移除 JDK 9 引入的实验性 AOT( Ahead-of-Time)编译和 JIT(Just-In-Time)编译器
- 强封装 JDK 内部 API:默认强封装
jdk.internal.*等内部 API,仅开放少数关键 API,增强安全性 - 弃用 Security Manager:标记
SecurityManager为弃用,准备未来移除(曾用于沙箱安全,现已被更现代的安全机制替代) - 移除 Applet API:彻底移除早已过时的 Applet 相关类(
java.applet包) - ZGC 和 Shenandoah 垃圾收集器转正:ZGC(低延迟)和 Shenandoah(低暂停)从实验性变为正式特性
- 其他改进:如java.util.random包新增随机数生成器、
String类新增indent()方法等
二、重要特性及代码示例
1. 密封类(Sealed Classes)
密封类通过sealed关键字声明,限制只有指定的子类(permits关键字指定)可以继承它,避免类被无限制扩展,增强代码的可维护性。
示例:密封类与允许的子类
// 密封类:仅允许Student和Teacher继承
public sealed class Person permits Student, Teacher {
protected String name;
public Person(String name) {
this.name = name;
}
public abstract String getRole();
}
// 允许的子类:可以是final(不可再继承)或non-sealed(可继续继承)
public final class Student extends Person {
private String studentId;
public Student(String name, String studentId) {
super(name);
this.studentId = studentId;
}
@Override
public String getRole() {
return "Student";
}
}
// 允许的子类:non-sealed表示可被其他类继承
public non-sealed class Teacher extends Person {
private String subject;
public Teacher(String name, String subject) {
super(name);
this.subject = subject;
}
@Override
public String getRole() {
return "Teacher";
}
}
// 错误:不允许继承密封类Person(未在permits中声明)
// public class Staff extends Person { ... } // 编译报错
2. 模式匹配的instanceof
传统instanceof需要先判断类型,再强制转换,代码冗余。JDK 17 中,instanceof可直接绑定变量,自动完成转换,简化逻辑。
示例:模式匹配简化类型处理
public class PatternMatchingExample {
public static void main(String[] args) {
Object obj = "Hello, JDK 17";
// 传统方式:判断后需手动转换
if (obj instanceof String) {
String s = (String) obj; // 冗余转换
System.out.println("长度:" + s.length());
}
// JDK 17:模式匹配,直接绑定变量s(自动转换)
if (obj instanceof String s) {
System.out.println("长度:" + s.length()); // 直接使用s,无需转换
}
// 结合条件判断
if (obj instanceof String s && s.length() > 5) {
System.out.println("长字符串:" + s); // 输出:长字符串:Hello, JDK 17
}
}
}
3. 增强的switch表达式
JDK 17 的switch支持:
- 箭头语法(
->):简化分支逻辑,无需break yield关键字:返回分支结果- 模式匹配:可根据类型、枚举等模式匹配分支
示例:switch的模式匹配与箭头语法
public class EnhancedSwitchExample {
public static String format(Object obj) {
// 基于类型模式的switch(匹配obj的实际类型)
return switch (obj) {
case Integer i -> String.format("整数:%d", i);
case String s -> String.format("字符串:%s", s);
case Double d -> String.format("小数:%.2f", d);
// 多个常量合并(如null和默认情况)
case null, default -> "未知类型";
};
}
public static void main(String[] args) {
System.out.println(format(100)); // 输出:整数:100
System.out.println(format("test")); // 输出:字符串:test
System.out.println(format(3.1415)); // 输出:小数:3.14
System.out.println(format(null)); // 输出:未知类型
}
}
4. 记录类(Records)
记录类(record)是不可变数据载体类的简化语法,自动生成equals()、hashCode()、toString()和字段访问方法,无需手动编写。
示例:记录类替代传统数据类
// 记录类:自动包含name和age字段,及相关方法
public record User(String name, int age) {
// 可自定义构造器(需调用默认构造器)
public User {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
}
// 可添加额外方法
public String getGreeting() {
return "Hello, " + name;
}
}
public class RecordExample {
public static void main(String[] args) {
User user = new User("Alice", 30);
System.out.println(user.name()); // 自动生成的访问方法
System.out.println(user.age());
System.out.println(user); // 自动生成的toString():User[name=Alice, age=30]
User user2 = new User("Alice", 30);
System.out.println(user.equals(user2)); // 自动生成的equals():true
}
}
5. 外部函数与内存 API(预览)
该 API 允许 Java 安全地调用本地代码(如 C 语言库)和访问本地内存,替代复杂且不安全的 JNI(Java Native Interface)。
示例:调用本地strlen函数计算字符串长度
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
import static java.lang.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.JAVA_LONG;
public class ForeignFunctionExample {
public static void main(String[] args) throws Throwable {
// 加载C标准库(不同系统路径可能不同,如Windows为"msvcrt.dll")
try (Arena arena = Arena.ofConfined()) { // 内存 arena 管理本地内存
// 查找本地函数"strlen"(计算字符串长度)
SymbolLookup stdlib = SymbolLookup.loaderLookup();
MethodHandle strlen = Linker.nativeLinker()
.downcallHandle(
stdlib.find("strlen").orElseThrow(),
FunctionDescriptor.of(JAVA_LONG, ADDRESS) // 函数签名:long strlen(char*)
);
// 分配本地内存并存储字符串
MemorySegment str = arena.allocateFrom("Hello");
// 调用本地函数strlen
long length = (long) strlen.invoke(str);
System.out.println("字符串长度:" + length); // 输出:5
}
}
}
6. 向量 API(第二次孵化)
向量 API 提供了一种与平台无关的方式编写向量计算代码,可被 JVM 优化为硬件特定的向量指令(如 AVX、SSE),显著提升数值计算性能(如图像处理、科学计算)。
示例:向量计算加速数组元素相加
import jdk.incubator.vector.*;
public class VectorExample {
private static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
// 向量加速的数组相加
public static void vectorAdd(float[] a, float[] b, float[] c) {
int i = 0;
int upperBound = SPECIES.loopBound(a.length);
// 向量批量处理
for (; i < upperBound; i += SPECIES.length()) {
FloatVector va = FloatVector.fromArray(SPECIES, a, i);
FloatVector vb = FloatVector.fromArray(SPECIES, b, i);
va.add(vb).intoArray(c, i); // 向量相加并写入结果数组
}
// 处理剩余元素(非向量批量部分)
for (; i < a.length; i++) {
c[i] = a[i] + b[i];
}
}
public static void main(String[] args) {
float[] a = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
float[] b = {6.0f, 7.0f, 8.0f, 9.0f, 10.0f};
float[] c = new float[5];
vectorAdd(a, b, c);
for (float val : c) {
System.out.print(val + " "); // 输出:7.0 9.0 11.0 13.0 15.0
}
}
}
总结
JDK 17 作为 LTS 版本,聚焦于提升开发效率和运行时性能:密封类和模式匹配增强了代码的可读性和安全性;记录类简化了不可变数据类的定义;外部函数与内存 API 和向量 API 为高性能场景提供了新工具;ZGC 和 Shenandoah 的转正满足了低延迟应用的需求。这些特性使 JDK 17 成为企业级应用的理想选择,同时保持了对旧版本的良好兼容性。


370

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



