Java SE 22 新增特性
作者:Grey
原文地址:
源码
使用未命名的变量和模式
我们经常需要定义一些我们根本不需要的变量。常见的例子包括异常、lambda表达式,例如:
java
try {
String string = "xx";
int number = Integer.parseInt(string);
} catch (NumberFormatException e) {
System.err.println("Not a number");
}
如果异常变量 e 无须使用,那么上述例子中的变量 e 可以用 _ 代替
java
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 代码:
java
public class Hello {
public static void main(String[] args) {
System.out.printf("Hello %s!%n", args[0]);
}
}
不需要 javac 编译这个程序,而是可以直接运行它:
cmd
java Hello.java
我们也可以在 Hello.java 文件中定义多个类。但是,随着程序的增长,这种做法很快就会变得混乱;其他类应该定义在单独的文件中,并以合理的包结构组织起来。
然而,一旦我们添加更多的 Java 文件,Java 11 中所谓的 "启动单个文件源代码 "机制就不再起作用了。
比如定义两个类:
java
public class Hello {
public static void main(String[] args) {
System.out.println(Greetings.greet(args[0]));
}
}
java
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 下,可以通过
cmd
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 "函数。
java
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 类,我们就可以像在连续文本中一样,将列表格式化为枚举。
java
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));
}
}
运行输出结果
java
Earth、Wind和Fire
Earth, Wind, and Fire
Earth, Wind und Fire
Earth, Wind et Fire
上述例子表明在不同的 Lacale 设置下,可自动根据配置进行格式化。