(附示例)Java 20 正式发布!7项新特性让开发更高效,包括虚拟线程、矢量 API、记录模式等

JDK 20已于2023年3月21日正式发布。它包含了 7 个JEP,其中包括来自AmberLoomPanama项目的新特性。例如,JEP 432:记录模式(Record Patterns,第二轮预览),JEP 433: switch 的模式匹配(Pattern Matching for switch,第四轮预览),JEP 434:外部函数与内存 API(Foreign Function & Memory API,第二轮预览)等等。

这些新特性如下:

JEP 429:作用域值(Scoped Values,孵化阶段):支持在线程内和跨线程共享不可变数据。

JEP 432:记录模式(Record Patterns,第二轮预览):允许您解构记录值,以实现对语言的增强。

JEP 433: switch 的模式匹配(Pattern Matching for switch,第四轮预览):通过将模式匹配扩展到 switch,可以针对多个模式测试表达式,每个模式都有特定的操作。

JEP 434:外部函数与内存 API(Foreign Function & Memory API,第二轮预览):允许 Java 程序更容易地与 Java 运行时之外的代码和数据进行互操作。

JEP 436:虚拟线程(Virtual Threads,第二轮预览):引入了虚拟线程,这是一种轻量级线程,可以极大地减少编写、维护和观测高吞吐量并发应用程序的工作量。

JEP 437:结构化并发(Structured Concurrency,第二轮孵化):通过将运行于不同线程中的多个任务视为一个工作单元,简化多线程编程。

JEP 438:Vector API(第五轮孵化):允许以一种在运行时,可靠地编译为支持的 CPU 架构上的向量指令方式表达向量计算,从而实现优于等效标量计算的性能。

这些新特性旨在提高开发人员的工作效率,并优化 Java 语言和平台。它们提供了更多的语言改进、更好的并发支持、更好的与本地代码的互操作性等等。

这是一些 JDK 20 新特性的示例:

JEP 429: 引入了作用域值,它允许在线程内和跨线程共享不可变数据。这些数据优先于线程局部变量,尤其是在使用大量虚拟线程时。下面是一个简单的示例,演示如何使用作用域值:

import java.lang.invoke.ScopeVarHandle;
import java.lang.invoke.VarHandle;

class Example {
    private static final VarHandle scopeVar = ScopeVarHandle.allocate(int.class);

    public static void main(String[] args) {
        try (var scope = ScopeVarHandle.open()) {
            scopeVar.set(scope, 42);
            new Thread(() -> {
                try (var threadScope = ScopeVarHandle.open()) {
                    System.out.println(scopeVar.get(threadScope)); // prints 42
                }
            }).start();
        }
    }
}

在上面的示例中,我们使用ScopeVarHandle.allocate方法为整数类型分配了一个作用域变量。然后,我们使用ScopeVarHandle.open方法打开一个新的作用域,并使用set方法设置作用域变量的值。在新线程中,我们再次打开一个新的作用域,并使用get方法获取作用域变量的值。由于作用域变量在线程间共享,因此新线程中获取的值与主线程中设置的值相同。

**JEP 432: **记录模式(第二预览版): 记录模式允许您解构记录值,以实现对语言的增强。例如,假设您有一个记录类Person,它有两个字段nameage。您可以使用记录模式在 switch 表达式中解构 Person 对象,如下所示:

Person person = new Person("John Doe", 42);
String message = switch (person) {
    case Person(String name, int age) -> "Name: " + name + ", Age: " + age;
    default -> "Unknown person";
};

JEP 433: Switch 模式匹配(第四预览版): 此 JEP 通过将模式匹配扩展到 switch,可以针对多个模式测试表达式,每个模式都有特定的操作。例如,假设您有一个对象obj,它可以是整数、字符串或其他类型。您可以使用 switch 模式匹配来检查其类型并执行相应的操作,如下所示:

String message = switch (obj) {
    case Integer i -> "Integer: " + i;
    case String s -> "String: " + s;
    default -> "Unknown type";
};

JEP 434: 外部函数和内存 API(第二预览版): 此 JEP 允许 Java 程序更容易地与 Java 运行时之外的代码和数据进行互操作。例如,您可以使用外部函数和内存 API 调用 C 库中的函数,如下所示:

MethodHandle strlen = CLinker.getInstance().downcallHandle(
    LibraryLookup.ofDefault().lookup("strlen").get(),
    MethodType.methodType(long.class, MemoryAddress.class),
    FunctionDescriptor.of(CLinker.C_LONG, CLinker.C_POINTER)
);
long length = (long) strlen.invokeExact(CLinker.toCString("Hello").address());

JEP 436: 虚拟线程(第二预览版): 此 JEP 引入了虚拟线程,这是一种轻量级线程,可以极大地减少编写、维护和观测高吞吐量并发应用程序的工作量。例如,您可以使用虚拟线程执行并发任务,如下所示:

Thread.startVirtualThread(() -> {
    // Task to be executed concurrently
});

JEP 437: 结构化并发(二次孵化阶段): 此 JEP 通过将运行于不同线程中的多个任务视为一个工作单元,简化多线程编程。例如,您可以使用结构化并发来执行多个并发任务并等待它们完成,如下所示:

try (StructuredTaskScope scope = new StructuredTaskScope()) {
    scope.schedule(() -> {
        // Task to be executed concurrently
    });
    scope.schedule(() -> {
        // Another task to be executed concurrently
    });
}

JEP 438: 矢量 API(五次孵化阶段): 此 JEP 允许以一种在运行时,可靠地编译为支持的 CPU 架构上的向量指令方式表达向量计算,从而实现优于等效标量计算的性能。例如,您可以使用矢量 API 执行向量加法,如下所示:

var a = IntVector.fromArray(IntVector.SPECIES_256, arrayA, 0);
var b = IntVector.fromArray(IntVector.SPECIES_256, arrayB, 0);
var c = a.add(b);
c.intoArray(arrayC, 0);