原文提供:
jdk17下载地址
JDK 17 文档 - 首页 (oracle.com)
概述(Java SE 17 和 JDK 17)
参考文档:https://openjdk.org/jeps/406
在Java 14和Java 15中,已经引入了Switch表达式的初始版本。而在JDK 17中,Switch表达式得到了一些改进和增强,包括以下新特性:
简化的Switch表达式:在JDK 17中,可以使用简化的Switch表达式来替代传统的Switch语句。这意味着Switch表达式可以像其他表达式一样返回一个值,无需使用break语句,并且每个分支只需要使用"->"符号来分隔条件和代码块。
示例:
int dayOfWeek = 5;
String dayType = switch (dayOfWeek) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "休息日";
default -> throw new IllegalArgumentException("无效的星期");
};
System.out.println(dayType); // 输出:工作日
jdk8编写
int dayOfWeek = 5;
String dayType;
switch (dayOfWeek) {
case 1:
case 2:
case 3:
case 4:
case 5:
dayType = "工作日";
break;
case 6:
case 7:
dayType = "休息日";
break;
default:
throw new IllegalArgumentException("无效的星期");
}
System.out.println(dayType); // 输出:无效的星期
新增的Pattern匹配:在JDK 17中,Switch表达式还支持对Pattern进行匹配。这使得我们可以使用Switch表达式来处理更复杂的模式匹配操作,例如对类型、枚举常量等进行匹配。
示例:
Object obj = "Hello";
int length = switch (obj) {
case String s -> s.length();
case Integer i && i > 0 -> i;
case int[] arr && arr.length > 0 -> arr.length;
default -> -1;
};
System.out.println(length); // 输出:5
jdk8编写
Object obj = "Hello";
int length;
if (obj instanceof String) {
String s = (String) obj;
length = s.length();
} else if (obj instanceof Integer && ((Integer) obj) > 0) {
int i = (Integer) obj;
length = i;
} else if (obj instanceof int[] && ((int[]) obj).length > 0) {
int[] arr = (int[]) obj;
length = arr.length;
} else {
length = -1;
}
System.out.println(length); // 输出:5
简化的Lambda类型:在JDK 17中,Switch表达式还支持使用"->"符号来指定Lambda表达式的类型。这使得我们可以更简洁地定义Switch表达式中的Lambda表达式。
示例:
int number = 4;
String numberType = switch (number) {
case 1 -> "One";
case 2 -> "Two";
case 3 -> "Three";
default -> {
yield "Other";
}
};
System.out.println(numberType); // 输出:Other
jdk8编写
int number = 4;
String numberType;
switch (number) {
case 1:
numberType = "One";
break;
case 2:
numberType = "Two";
break;
case 3:
numberType = "Three";
break;
default:
numberType = "Other";
break;
}
System.out.println(numberType); // 输出:Other
Switch表达式的新特性需要Java 17或更高版本才能使用。并且在使用Switch表达式时,仍然需要确保每个分支都能够处理所有可能的情况,否则需要在最后添加default分支来处理未匹配到的情况。
参考文档:https://openjdk.org/jeps/409
jdk15版本,作为预览功能提供,再次被提出,JDK16版本又作为预览功能,在JDK17中完善,与JDK16没有变化
sealed 类是 JDK 17 中引入的一个新特性,它通过控制类的直接子类来提供更严格的类继承关系,并对类层次结构进行限制。这有助于提高代码的可读性和可维护性,并在特定领域建模中非常有用。它通过控制类的直接子类来提供更严格的类继承关系,并对类层次结构进行限制。这有助于提高代码的可读性和可维护性,并在特定领域建模中非常有用。
public sealed class Student permits StudentSon1, StudentSon2 {
// 父类定义的共享属性和方法
}
final class StudentSon1 extends Student {
// 圆形特定的属性和方法
}
final class StudentSon2 extends Student {
// 矩形特定的属性和方法
}
解释:
通过sealed关键字定义的Student类,只能被permits关键字列出的StudentSon1,StudentSon2类来继承,其他类无法直接继承Student类,负责编译错误
这样的设计有助于受限制继承关系,使得只有特定的StudentSon1和StudentSon2来继承Student父类。
这种模式可以在建模特定领域或实现特定抽象时非常有用,因为它能提供更严格的类层次结构,增加代码的可读性和可维护性。
permits 是用于定义一个 sealed 类的子类集合的关键字。在一个 sealed 类的声明中,可以使用 permits 关键字来列出一组允许的子类,这些子类可以继承该 sealed 类。
当一个类被声明为 sealed 类时,它必须显式列出其所允许的所有直接子类。这个列表通过使用 permits 关键字来定义,其后跟随该 sealed 类所允许的子类名称或类型。例如:
public sealed class Animal permits Cat, Dog, Fish {
// 类主体
}
Animal 是一个 sealed 类,它允许的子类分别是 Cat、Dog 和 Fish。
需要注意的是,使用 permits 关键字列出的子类必须是 sealed 类、final 类或 non-sealed 类。如果不是这些类型之一,那么会出现编译时错误。
permits 是 Java 中用于定义 sealed 类的允许子类集合的关键字,它可以帮助开发人员更加精确地控制类的继承关系,提高代码的可读性和可维护性。
/*
定义一个sealed类,在permits列表中出现编译错误p.B
正确的写法是使用完整的包名前缀,例如 package.B
sealed class A 表示类 A 是一个 sealed 类,但由于permits列表中的子句错误,代码无法通过编译。
*/
sealed class A permits B, C, p.B {} // error
//类 B 是一个非 sealed 类,它继承自类 A。由于 A 是 sealed 类,所以 B 可以作为 A 的子类进行扩展。
non-sealed class B extends A {}
//类 C 是一个非 sealed 类,也继承自类 A。与类 B 一样,C 作为 A 的子类进行扩展。
non-sealed class C extends A {}
JDK17引入名为ZGC(Z Garbage Collector)是一种低延迟的垃圾回收器
。是JDK 11引入的一项实验性功能,并在JDK 15中成为稳定特性。
它旨在减少应用程序的停顿时间,使得即使在大内存堆上也能保持非常短的垃圾收集暂停时间。暂停时间与正在使用的堆大小无关。ZGC支持从8MB到16TB的堆大小。
Z 垃圾回收器使用命令行选项 启用。-XX:+UseZGC
尽管ZGC在降低停顿时间方面取得了显著的改进,但这并不意味着它适用于所有场景
。在某些情况下,特别是对于小内存堆或强调极致吞吐量的应用程序,其他垃圾收集器可能更合适。
因此,在选择垃圾收集器时,还需要综合考虑应用程序的性质和需求。
想要查看的第二个调整选项是 设置并发 GC 线程数 .ZGC具有自动选择此数字的启发式方法。这种启发式方法通常效果很好,但根据应用程序的特征,可能需要进行调整。此选项基本上决定了应该给 GC 多少 CPU 时间。给它太多,GC 将从应用程序中窃取太多的 CPU 时间。
给它太少,应用程序分配垃圾的速度可能会快于 GC 收集它的速度。(-XX:ConcGCThreads)
定义一个清理操作类,该类 初始化清理操作并定义清洁操作本身(通过 重写方法)。State``State::run()
创建 的实例。Cleaner
使用此实例 ,注册对象和清理操作(的实例)。Cleaner``myObject1``State
确保垃圾回收器安排清理程序和 在示例结束之前执行清理操作, 示例:
State::run()
myObject1``null
import java.lang.ref.Cleaner;
public class CleanerExample {
// 此清洁器由所有清洁器示例实例共享
private static final Cleaner CLEANER = Cleaner.create();
private final State state;
public CleanerExample(String id) {
state = new State(id);
CLEANER.register(this, state);
}
// Cleaner的动作类
private static class State implements Runnable {
final private String id;
private State(String id) {
this.id = id;
System.out.println("Created cleaning action for " + this.id);
}
@Override
public void run() {
System.out.println("Cleaner garbage collected " + this.id);
}
}
public static void main(String[] args) {
CleanerExample myObject1 = new CleanerExample("myObject1");
//设置myObject1不可达
myObject1 = null;
System.out.println("-- Give the GC a chance to schedule the Cleaner --");
for (int i = 0; i < 100; i++) {
//在循环中调用System.gc()通常足以触
//像这样的小程序的清理。
System.gc();
try {
Thread.sleep(1);
} catch (InterruptedException e) {}
}
System.out.println("-- Finished --");
}
}
输出内容
Created cleaning action for myObject1
-- Give the GC a chance to schedule the Cleaner --
Cleaner garbage collected myObject1
-- Finished --
该代码示例演示了Java中的Cleaner类的用法。
Cleaner类是Java 9引入的一个新特性,用于实现在对象被垃圾回收之前执行必要的清理操作。
这段代码定义了一个CleanerExample类,其中包含一个静态的Cleaner实例和一个私有的State内部类,实现了Runnable接口。
在CleanerExample的构造函数中,每次创建实例时都会注册当前对象和其状态(State)到Cleaner中。在State的构造函数中,会打印出创建清理操作的信息。
在main方法中,首先创建了一个CleanerExample实例。然后将myObject1设置为null,使其变得不可达。
接下来,进入一个循环并在循环中调用System.gc(),以尝试手动触发垃圾回收。在每次循环迭代中,通过调用Thread.sleep()来暂停一小段时间,给垃圾回收器调度Cleaner的机会。
最后,程序输出"-- Finished --"表示程序执行结束。
注意: 尽管ZGC在降低停顿时间方面取得了显著的改进,但这并不意味着它适用于所有场景。在某些情况下,特别是对于小内存堆或强调极致吞吐量的应用程序,其他垃圾收集器可能更合适。因此,在选择垃圾收集器时,还需要综合考虑应用程序的性质和需求。
参考文档:https://openjdk.org/jeps/395
Record Classes 最初定义在14版本作为预览功能提供,在15版本中作为第二次预览功能,
最后在16版本完成相关功能,后续可能会有相关改进
equals
public class RecordClassExample {
public static void main(String[] args) {
// 创建 Person 对象
Person person = new Person("Alice", 25);
// 使用 getter 方法获取字段值
String name = person.name();
int age = person.age();
// 打印字段值
System.out.println("Name: " + name);
System.out.println("Age: " + age);
}
// 定义一个 Person Record Class
public record Person(String name, int age) {
// 构造函数和 getter 方法由编译器自动生成
}
}
参考文档:https://openjdk.org/jeps/378
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
TextBlocks最初定义在12版本,又被撤销掉了。有在13版本中出现,并定稿,在后续的迭代改进中,成为了最终和永久性的正式标准功能,无需进一步改进
在之前的 Java 版本中,编写多行字符串需要使用转义字符和连接符号,使得代码变得复杂和不够清晰。而通过 Text Blocks,可以将一个多行字符串定义在一对三重双引号(“”")之间,无需转义字符或连接符号。
Text Blocks 不仅可以保留字符串内的换行符,还可以通过缩进控制字符串的格式。这在编写 HTML、JSON、SQL 等格式化字符串时非常有用。
一维字符串文本
String html = "\n" +
" \n" +
" Hello, world
\n" +
" \n" +
"\n";
二维文本块
String html = """
Hello, world
""";
一维字符串文本
String query = "SELECT \"EMP_ID\", \"LAST_NAME\" FROM \"EMPLOYEE_TB\"\n" +
"WHERE \"CITY\" = 'INDIANAPOLIS'\n" +
"ORDER BY \"EMP_ID\", \"LAST_NAME\";\n";
二维文本块
String query = """
SELECT "EMP_ID", "LAST_NAME" FROM "EMPLOYEE_TB"
WHERE "CITY" = 'INDIANAPOLIS'
ORDER BY "EMP_ID", "LAST_NAME";
""";
一维字符串文本
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("function hello() {\n" +
" print('\"Hello, world\"');\n" +
"}\n" +
"\n" +
"hello();\n");
二维文本块
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval("""
function hello() {
print('"Hello, world"');
}
hello();
""");
idea22版本以下不支持jkd17