Java SE 23 新增特性
作者:Grey
原文地址:
部落格園:Java SE 23 新增特性
CSDN:Java SE 23 新增特性
原始碼
源倉庫: Github:java_new_features
Primitive Types in Patterns, instanceof, and switch (預覽功能)
透過 instanceof 和 switch,我們可以檢查物件是否屬於特定型別,如果是,則將該物件繫結到該型別的變數,執行特定的程式路徑,並在該程式路徑中使用新變數。
public class PrimitiveTypesTest {
void main() {
test1("hello world");
test2("hello world");
test1(56);
test2(56);
test1(java.time.LocalDate.now());
test2(java.time.LocalDate.now());
}
private static void test1(Object obj) {
if (obj instanceof String s && s.length() >= 5) {
System.out.println(s.toUpperCase());
} else if (obj instanceof Integer i) {
System.out.println(i * i);
} else {
System.out.println(obj);
}
}
private static void test2(Object obj) {
switch (obj) {
case String s when s.length() >= 5 -> System.out.println(s.toUpperCase());
case Integer i -> System.out.println(i * i);
case null, default -> System.out.println(obj);
}
}
}
JEP 455 在 Java 23 中引入了兩項變更:
-
可以在 switch 表示式和語句中使用所有基元型別,包括 long、float、double 和 boolean。
-
其次,我們還可以在模式匹配中使用所有基元型別,包括 instanceof 和 switch。
在這兩種情況下,即透過 long、float、double 和布林型別進行 switch 以及使用基元變數進行模式匹配時,與所有新的 switch 功能一樣,switch 必須要涵蓋所有可能的情況。
private static void test3(int x) {
switch (x) {
case 1, 2, 3 -> System.out.println("Low");
case 4, 5, 6 -> System.out.println("Medium");
case 7, 8, 9 -> System.out.println("High");
}
}
Module Import Declarations (模組匯入宣告,預覽功能)
透過簡潔地匯入模組匯出的所有包的功能來增強 Java 程式語言。這簡化了模組庫的重複使用,但不要求匯入程式碼本身必須在模組中。這是一項預覽語言功能。
自 Java 1.0 起,java.lang
包中的所有類都會自動匯入到每個 .java 檔案中。這就是為什麼我們無需匯入語句就能使用 Object
、String
、Integer
、Exception
、Thread
等類的原因。
我們還可以匯入完整的包。例如,匯入 java.util.*
意味著我們不必單獨匯入 List
、Set
、Map
、ArrayList
、HashSet
和 HashMap
等類。
JEP 467現在允許我們匯入完整的模組,更準確地說,是匯入模組匯出的包中的所有類。
例如,我們可以按如下方式匯入完整的 java.base
模組,然後使用該模組中的類(例如 List
、Map
、Collectors
、Stream
),而無需進一步匯入:
package git.snippets.jdk23;
import module java.base;
public class ModuleImportDeclarationsTest {
void main() {
System.out.println(groupByFirstLetter("a", "abc", "bcd", "ddd", "dddc", "dfc", "bc"));
}
public static Map<Character, List<String>> groupByFirstLetter(String... values) {
return Stream.of(values).collect(Collectors.groupingBy(s -> Character.toUpperCase(s.charAt(0))));
}
}
如果有兩個同名的匯入類,例如下面示例中的 Date,編譯器就會出錯:
import module java.base;
import module java.sql;
如果一個匯入模組臨時匯入了另一個模組,那麼我們也可以使用臨時匯入模組匯出包中的所有類,而無需顯式匯入。
例如,java.sql 模組轉義匯入了 java.xml 模組:
module java.sql {
. . .
requires transitive java.xml;
. . .
}
因此,在下面的示例中,我們不需要顯式匯入 SAXParserFactory 和 SAXParser,也不需要顯式匯入 java.xml 模組:
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
Flexible Constructor Bodies (二次預覽)
在 JDK 23 之前,下述程式碼中,Child1的建構函式,只能先透過super構造父類,然後才能初始化子類的 b 這個變數。
public class FlexibleConstructorBodies {
void main() {
new Child1(1, 2);
}
}
class Parent {
private final int a;
public Parent(int a) {
this.a = a;
printMe();
}
void printMe() {
System.out.println("a = " + a);
}
}
// JDK 23 之前
class Child1 extends Parent {
private final int b;
public Child1(int a, int b) {
super(verifyParamsAndReturnA(a, b));
this.b = b;
}
@Override
void printMe() {
super.printMe();
System.out.println("b = " + b);
}
private static int verifyParamsAndReturnA(int a, int b) {
if (a < 0 || b < 0) throw new IllegalArgumentException();
return a;
}
}
當我們執行
new Child1(1,2);
這段程式碼的時候,本來我們期待返回的是
a = 1
b = 2
但是由於父類在構造時候呼叫了printMe()
,且這個呼叫是在 b 變數初始化之前呼叫的,所以導致程式執行的結果是
a = 1
b = 0
今後,在使用 super(...) 呼叫超級建構函式之前,以及在使用 this(...) 呼叫替代建構函式之前,我們可以執行任何不訪問當前構造例項(即不訪問其欄位)的程式碼
此外,我們還可以初始化正在構造的例項的欄位。詳見JEP 482
在 JDK 23 上,上述程式碼可以調整為:
class Child2 extends Parent {
private final int b;
public Child2(int a, int b) {
if (a < 0 || b < 0) throw new IllegalArgumentException(); // ⟵ Now allowed!
this.b = b; // ⟵ Now allowed!
super(a);
}
@Override
void printMe() {
super.printMe();
System.out.println("b = " + b);
}
}
其中建構函式中,a和b的初始化和判斷,都可以在super(...)函式呼叫之前,
執行
new Child2(1,2);
列印結果為預期結果
a = 1
b = 2
Implicitly Declared Classes and Instance Main Methods (第三次預覽)
最早出現在 JDK 21 中,見Java SE 21 新增特性
原來我們寫一個main方法,需要
public class UnnamedClassesAndInstanceMainMethodsTest {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
而且Java檔案的名稱需要和UnnamedClassesAndInstanceMainMethodsTest保持一致,到了JDK 23,上述程式碼可以簡化成
void main() {
System.out.println("hello world");
}
甚至連 public class ... 這段也不需要寫。
更多
Java SE 7及以後各版本新增特性,持續更新中...
參考資料
Java Language Changes for Java SE 23
JDK 23 Release Notes
JAVA 23 FEATURES(WITH EXAMPLES