Java SE 22 新增特性
作者:Grey
原文地址:
源碼
使用未命名的變量和模式
我們經常需要定義一些我們根本不需要的變量。常見的例子包括異常、lambda表達式,例如:
try {
String string = "xx";
int number = Integer.parseInt(string);
} catch (NumberFormatException e) {
System.err.println("Not a number");
}
如果異常變量 e 無須使用,那麼上述例子中的變量 e 可以用 _ 代替
try {
String string = "xx";
int number = Integer.parseInt(string);
} catch (NumberFormatException _) {
System.err.println("Not a number");
}
這個功能在 Java SE 21 中作爲預覽功能發佈,詳見Java SE 21 新增特性,在 Java 22 中通過 JEP 456 最終確定,不會有任何更改。
啓動多文件源代碼程序
自 Java 11 起,我們可以直接執行僅由一個文件組成的 Java 程序,而無需先對其進行編譯,詳見Java SE 11 新增特性
例如,在 Hello.java 文件中保存一次以下 Java 代碼:
public class Hello {
public static void main(String[] args) {
System.out.printf("Hello %s!%n", args[0]);
}
}
不需要 javac 編譯這個程序,而是可以直接運行它:
java Hello.java
我們也可以在 Hello.java 文件中定義多個類。但是,隨着程序的增長,這種做法很快就會變得混亂;其他類應該定義在單獨的文件中,並以合理的包結構組織起來。
然而,一旦我們添加更多的 Java 文件,Java 11 中所謂的 "啓動單個文件源代碼 "機制就不再起作用了。
比如定義兩個類:
public class Hello {
public static void main(String[] args) {
System.out.println(Greetings.greet(args[0]));
}
}
public class Greetings {
public static String greet(String name) {
return "Hello %s!%n".formatted(name);
}
}
在 Java SE 11 中,無法執行,因爲只支持單個 Java 文件運行,但是到了 Java SE 22,可以支持多個文件源碼運行,比如上述兩個類,在 Java SE 22 下,可以通過
java Hello.java
運行。
Foreign Function 和 Memory API
在Project Panama中,取代繁瑣、易出錯、速度慢的 Java 本地接口(JNI)的工作已經進行了很長時間。
在 Java 14 和 Java 16 中已經引入了 "外來內存訪問 API "和 "外來鏈接器 API"--最初都是單獨處於孵化階段。在 Java 17 中,這些 API 被合併爲 "Foreign Function & Memory API"(FFM API),直到 Java 18,它一直處於孵化階段。
在 Java 19 中,JDK Enhancement Proposal 424最終將新的 API 提升到了預覽階段,
在 Java SE 22 中,外來函數與內存 API 終於由 JDK Enhancement Proposal 454 最終確定。
FFM API 可以直接從 Java 訪問本地內存(即 Java 堆外的內存)和訪問本地代碼(如 C 庫)。
下面是一個簡單的例子,它在堆外內存中存儲一個字符串,並對其調用 C 語言標準庫的 "strlen "函數。
package git.snippets.jdk22;
import java.lang.foreign.*;
import java.lang.invoke.MethodHandle;
/**
* FFM API
* @since 22
*/
public class FFMTest {
public static void main(String[] args) throws Throwable {
// 1. Get a lookup object for commonly used libraries
SymbolLookup stdlib = Linker.nativeLinker().defaultLookup();
// 2. Get a handle to the "strlen" function in the C standard library
MethodHandle strlen = Linker.nativeLinker().downcallHandle(stdlib.find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));
// 3. Get a confined memory area (one that we can close explicitly)
try (Arena offHeap = Arena.ofConfined()) {
// 4. Convert the Java String to a C string and store it in off-heap memory
MemorySegment str = offHeap.allocateFrom("Happy Coding!");
// 5. Invoke the foreign function
long len = (long) strlen.invoke(str);
System.out.println("len = " + len);
}
// 6. Off-heap memory is deallocated at end of try-with-resources
}
}
本地化列表
Java SE 22 有了新的 ListFormat 類,我們就可以像在連續文本中一樣,將列表格式化爲枚舉。
package git.snippets.jdk22;
import static java.text.ListFormat.*;
import java.text.ListFormat;
import java.util.List;
import java.util.Locale;
public class LocaleDependentListPatternsTest {
void main() {
List<String> list = List.of("Earth", "Wind", "Fire");
System.out.println(ListFormat.getInstance(Locale.CHINA, Type.STANDARD, Style.FULL).format(list));
System.out.println(ListFormat.getInstance(Locale.US, Type.STANDARD, Style.FULL).format(list));
System.out.println(ListFormat.getInstance(Locale.GERMAN, Type.STANDARD, Style.FULL).format(list));
System.out.println(ListFormat.getInstance(Locale.FRANCE, Type.STANDARD, Style.FULL).format(list));
}
}
運行輸出結果
Earth、Wind和Fire
Earth, Wind, and Fire
Earth, Wind und Fire
Earth, Wind et Fire
上述例子表明在不同的 Lacale 設置下,可自動根據配置進行格式化。