一、前言
JDK 21 于 2023 年 9 月发布,作为目前讨论热度最高的JDK,虽然大家都开玩笑说你发任你发,我用Java8
,但是作为一个Javaer,对JDK21的新特性还是要有所了解的。
以下是 JDK 21 的新功能列表:
- 虚拟线程
- 序列集合
- 记录模式
- 字符串模板(预览)
- 未命名模式和变量(预览)
- 未命名类和实例主要方法(预览)
- 作用域值(预览)
- 结构化并发(预览)
JDK21下载地址:JDK官网
安装过程在这里就不赘述了,正常【下一步】就行了。
二、新特性体验
1. switch 模式匹配
可以通过switch表达式和语句的模式匹配来增强Java编程语言,可以针对多个模式测试表达式,每个模式都有一个特定的操作,从而可以简洁、安全地表达复杂的面向数据的查询。
1.1 支持返回值,不用写break
示例代码:
public class SwitchTest {
public static void main(String[] args) {
String unit = "cm";
String str = switch (unit) {
case "cm" -> "厘米";
case "m" -> "米";
case "mm" -> "毫米";
case "km" -> "千米";
default -> "错误";
};
System.out.println(str);
}
}
测试结果:
注意:如果执行结果乱码,可以参考如下操作进行:
-
增加VM参数
-
修改文件编码
1.2 如果需要执行多行代码再返回,可使用yield关键字
示例代码:
public class SwitchTest {
public static void main(String[] args) {
String unit = "cm";
String str = switch (unit) {
case "cm" -> {
System.out.println("我在测试呢...");
yield "厘米";
}
case "m" -> "米";
case "mm" -> "毫米";
case "km" -> "千米";
default -> "错误";
};
System.out.println(str);
}
}
1.3 多值匹配
示例代码:
public class SwitchTest {
public static void main(String[] args) {
String unit = "cm";
String str = switch (unit) {
case "cm", "m" -> "厘米";
case "mm" -> "毫米";
case "km" -> "千米";
default -> "错误";
};
System.out.println(str);
}
}
1.4 null值处理
示例代码:
public class SwitchTest {
public static void main(String[] args) {
String unit = null;
String str = switch (unit) {
case "cm", "m" -> "厘米";
case "mm" -> "毫米";
case "km" -> "千米";
case null -> "未知";
default -> "错误";
};
System.out.println(str);
}
}
1.5 匹配增强
示例代码:
public class SwitchTest {
public static void main(String[] args) {
Double obj = 0.0d;
String str = switch (obj) {
case Integer i -> String.format("int %d", i);
case Long l -> String.format("long %d", l);
case Double d -> String.format("double %f", d);
case String s -> String.format("String %s", s);
default -> obj.toString();
};
System.out.println(str);
}
}
2. 记录模式
记录模式,也就是记录模式匹配,英文为“Record Patterns”,记录模式匹配是指自动匹配Record记录类,从而简化代码。Record记录会自动生成了构造函数、getter、equals、hashCode、toString等方法,简化代码的编写,类似于lombok插件的@Data注解,但是对象属性只读,只有get方法,没有set方法。
-
使用class
public class User { private String name; private Integer age; public User(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public Integer getAge() { return age; } }
-
使用record
public record User(String name, Integer age) { }
3. 字符串模板
示例代码:
public class StrTest {
public static void main(String[] args) {
String name = "JDK21";
String message = STR."Hello \{name}!";
System.out.println(message);
}
}
注意这是预览功能,默认禁用,我们需要使用--enable-preview
启用字符串模板。
在Idea中,我们需要额外设置:
--enable-preview --source 21 -Xlint:preview
4. 顺序集合
SequencedSet 接口对于具有有序元素的 Set 非常有用,特别是当您必须执行某些操作(例如检索或删除第一个或最后一个索引处的元素)时。它还提供了一种反转元素的方法。
-
List
import java.util.LinkedHashSet; import java.util.SequencedSet; public class ListTest { public static void main(String[] args) { SequencedSet<String> values = new LinkedHashSet<>(); values.add("one"); values.add("two"); System.out.println(values); // [one, two] values.addFirst("zero"); System.out.println(values); // [zero, one, two] values.addFirst("one"); System.out.println(values); // [one, zero, two] values.addLast("three"); System.out.println(values); // [one, zero, two, three] SequencedSet<String> reversedSet = values.reversed(); System.out.println(reversedSet); // [three, two, zero, one] } }
-
Map
import java.util.LinkedHashMap; import java.util.Map; import java.util.SequencedMap; public class MapTest { public static void main(String[] args) { SequencedMap<String, Integer> myMap = new LinkedHashMap<>(); myMap.put("one", 1); myMap.put("two", 2); System.out.println(myMap); // {one=1, two=2} Map.Entry<String, Integer> firstEntry = myMap.firstEntry(); System.out.println(firstEntry); // one=1 Map.Entry<String, Integer> lastEntry = myMap.lastEntry(); System.out.println(lastEntry); // two=2 myMap.putFirst("zero", 0); System.out.println(myMap); // {zero=0, one=1, two=2} myMap.putFirst("one", -1); System.out.println(myMap); // {one=-1, zero=0, two=2} Map.Entry<String, Integer> polledFirstEntry = myMap.pollFirstEntry(); System.out.println(polledFirstEntry); // one=-1 System.out.println(myMap); // {zero=0, two=2} SequencedMap<String, Integer> reversedMap = myMap.reversed(); System.out.println(reversedMap); // {two=2, zero=0} } }
5. 虚拟线程
虚拟线程是Jdk21的重头戏,从 Java 代码的角度来看,虚拟线程感觉就像普通线程,但它们没有 1:1 映射到操作系统/平台线程。它是从虚拟线程到载体线程进而到操作系统线程的M:N映射。
虚拟线程的一些优点:
-
提高应用程序吞吐量
-
提高应用程序可用性
-
减少内存消耗
示例代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class VirtualThreadsTest {
public static void main(String[] args) {
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor();
for (int i = 0; i < 10; i++) {
int taskId = i;
executor.execute(() -> {
System.out.println("Task " + taskId + " is running on virtual thread: " + Thread.currentThread().getName());
});
}
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
executor.shutdown();
}
}