Java 21 中的新特性
1. 概述
Oracle 於 2023 年 9 月 19 日發布了 Java 21。它是繼 Java 17 之後最新的 Java LTS 版本。
本文將討論Java 21 中新增的新功能和增強功能。
2. JEP清單
讓我們談談透過各種 Java 增強提案 (JEP) 在 Java 21 中對該語言引入的顯著增強。
2.1.記錄模式 ( JEP 440 )
記錄模式作為預覽功能包含在 Java 19 和 Java 20 中,Java 21 進一步完善了此功能。
此 JEP 擴展了現有的模式匹配功能來解構記錄類別實例,從而可以編寫複雜的資料查詢。還增加了對嵌套模式的支持,以實現更多可組合的資料查詢。
這是一個例子:
record Point(int x, int y) {}
public static int beforeRecordPattern(Object obj) {
int sum = 0;
if(obj instanceof Point p) {
int x = px();
int y = py();
sum = x+y;
}
return sum;
}
public static int afterRecordPattern(Object obj) {
if(obj instanceof Point(int x, int y)) {
return x+y;
}
return 0;
}
我們也可以使用嵌套記錄模式。以下範例示範了這一點:
enum Color {RED, GREEN, BLUE}
record ColoredPoint(Point point, Color color) {}
record RandomPoint(ColoredPoint cp) {}
public static Color getRamdomPointColor(RandomPoint r) {
if(r instanceof RandomPoint(ColoredPoint cp)) {
return cp.color();
}
return null;
}
在上面的程式碼片段中,我們解構ColoredPoint
以存取color()
方法。
2.2. switch
的模式匹配 ( JEP 441 )
switch
的模式匹配在 JDK 17 中引入,並在 JDK 18、19、20 和 JDK 21 中進行了完善。
此功能的主要目標是**允許switch case
標籤中存在模式,以提高switch
語句和表達式的表達能力**。此外,還透過允許null case
標籤來增強處理NullPointerException
。
讓我們透過一個例子來探討這個問題:
class Account{
double getBalance() {
return 0;
}
}
class SavingsAccount extends Account {
double getBalance() {
return 100;
}
}
class TermAccount extends Account {
double getBalance() {
return 1000;
}
}
class CurrentAccount extends Account {
double getBalance() {
return 10000;
}
}
在Java 21之前,我們可以使用下面的程式碼來取得餘額:
static double getBalanceWithOutSwitchPattern(Account account) {
double balance = 0;
if(account instanceof SavingsAccount sa) {
balance = sa.getBalance();
}
else if(account instanceof TermAccount ta) {
balance = ta.getBalance();
}
else if(account instanceof CurrentAccount ca) {
balance = ca.getBalance();
}
return balance;
}
上面的程式碼表達能力不是很強。透過 Java 21,我們可以利用case
標籤中的模式:
static double getBalanceWithSwitchPattern(Account account) {
double result = 0;
switch (account) {
case null -> throw new RuntimeException("Oops, account is null");
case SavingsAccount sa -> result = sa.getBalance();
case TermAccount ta -> result = ta.getBalance();
case CurrentAccount ca -> result = ca.getBalance();
default -> result = account.getBalance();
};
return result;
}
模式case
標籤也支援許多值。讓我們透過一個例子來詳細說明這一點:
static String processInputOld(String input) {
String output = null;
switch(input) {
case null -> output = "Oops, null";
case String s -> {
if("Yes".equalsIgnoreCase(s)) {
output = "It's Yes";
}
else if("No".equalsIgnoreCase(s)) {
output = "It's No";
}
else {
output = "Try Again";
}
}
}
return output;
}
可以使用帶有case
標籤的 Java 21 的when
子句來增強上面的程式碼:
static String processInputNew(String input) {
String output = null;
switch(input) {
case null -> output = "Oops, null";
case String s when "Yes".equalsIgnoreCase(s) -> output = "It's Yes";
case String s when "No".equalsIgnoreCase(s) -> output = "It's No";
case String s -> output = "Try Again";
}
return output;
}
2.3.字串文字 ( JEP 430 )
Java 提供了多種以字串文字和表達式組成字串的機制。其中一些是 String 連線、 StringBuilder
類別、 String
類別format()
方法和MessageFormat
類別。
Java 21 引入了**字串模板**。透過將文字文字與模板表達式和模板處理器耦合來產生所需的結果,這補充了 Java 現有的字串文字和文字區塊。
讓我們來看一個例子:
String name = "Baeldung";
String welcomeText = STR."Welcome to \{name}";
System.out.println(welcomeText);
上面的程式碼片段列印文字“ Welcome to Baeldung
”。
在上面的文字中,我們有一個模板處理器 (STR)、一個點字元和一個包含嵌入表達式 ( \{name}
) 的模板。在運行時,當模板處理器計算模板表達式時,它將模板中的文字文字與嵌入表達式的值組合起來以產生結果。
STR 是 Java 提供的模板處理器之一,會自動匯入所有 Java 原始檔。 Java 提供的其他模板處理器是 FMT 和 RAW。
2.4.虛擬線程 ( JEP 444 )
虛擬執行緒最初作為 Java 19 中的預覽功能引入到 Java 語言中,並在 Java 20 中進一步完善。Java 21 引入了一些新的變更。
虛擬線程是輕量級線程。這些執行緒的主要目的之一是減少開發高並發應用程式的工作量。傳統線程也稱為平台線程,是作業系統線程的薄包裝器。平台執行緒的主要問題之一是它們在作業系統執行緒上運行程式碼並在其整個生命週期中捕獲作業系統執行緒。作業系統執行緒的數量是有限的,這會造成可擴展性瓶頸。
與平台執行緒一樣,虛擬執行緒也是java.lang.Thread
類別的實例,但它不依賴特定的作業系統執行緒。它在特定作業系統執行緒上運行程式碼,但不會在整個生命週期內捕獲該執行緒。因此,許多虛擬執行緒可以共享作業系統執行緒來運行它們的程式碼。
讓我們透過一個例子來看看虛擬線程的使用:
try(var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.rangeClosed(1, 10_000).forEach(i -> {
executor.submit(() -> {
System.out.println(i);
try {
Thread.sleep(Duration.ofSeconds(1));
}
catch (InterruptedException e) {
e.printStackTrace();
}
});
});
}
在上面的程式碼片段中,我們使用靜態newVirtualThreadPerTaskExecutor()
方法。此執行器為每個任務建立一個新的虛擬執行緒。因此,在上面的例子中,我們創建了10000
虛擬線程。
Java 21 對虛擬執行緒引入了兩個顯著的變化:
- 虛擬線程現在始終支援線程局部變數。
- 虛擬執行緒是透過
Thread.Builder
API 創建的,也透過其生命週期進行監控,並可在新的執行緒轉儲中觀察到
2.5.序列集合( JEP 431 )
在 Java 集合框架中,沒有集合類型表示具有定義的遇到順序的元素序列。例如, List
和Deque
介面定義了遇到順序,但它們的公共超類型Collection
沒有定義。同樣, Set
不定義遇到順序,但LinkedHashSet
或SortedSet
等子類型定義了遇到順序。
Java 21 引入了三個新介面來表示順序集合、順序集合和順序映射。
排序集合是其元素具有定義的遇到順序的集合。它有第一個和最後一個元素,它們之間的元素有後繼者和前驅者。有序集是一個沒有重複元素的有序集合。排序映射是其條目具有定義的遇到順序的映射。
下圖展示了集合框架層次結構中新引入的介面的改造:
2.6。金鑰封裝機制 API ( JEP 452 )
金鑰封裝是一種使用非對稱金鑰或公鑰加密來保護對稱金鑰的技術。
傳統方法使用公鑰來保護隨機產生的對稱金鑰。然而,這種方法需要填充,這很難證明安全。
金鑰封裝機制 (KEM) 使用公鑰來衍生不需要任何填入的對稱金鑰。
Java 21 引入了新的 KEM API,使應用程式能夠使用 KEM 演算法。
三、結論
在本文中,我們討論了 Java 21 中提供的一些值得注意的變更。
我們討論了記錄模式、開關模式匹配、字串模板、排序集合、虛擬線程、字串模板和新的 KEM API。
JDK 21 套件和類別中還存在其他增強和改進。不過,本文應該是探索 Java 21 新功能的好起點。
與往常一樣,本文的源代碼可在 GitHub 上取得。