Java 19的新特性

发布时间:2023-11-23 10:04
最后更新:2024-09-02 22:42
所属分类:
JVM Java

Java 19同样是一个小的进化版本,相比Java 18并没有引入更多稳定发布的功能,而是继续对即将要加入的功能进行孵化和预览。

Java 19计划于2022年9月发布,但是因为其并非长期支持版本,故不建议在生产环境中优先选择使用。

本系列的文章有:

  1. Java 8的新特性
  2. Java 9的新特性
  3. Java 10的新特性
  4. Java 11的新特性
  5. Java 12的新特性
  6. Java 13的新特性
  7. Java 14的新特性
  8. Java 15的新特性
  9. Java 16的新特性
  10. Java 17的新特性
  11. Java 18的新特性
  12. Java 19的新特性
  13. Java 20的新特性
  14. Java 21的新特性

功能提案

在Java 19中主要增加了以下提案中的功能:

在这些功能提案中有一些属于老生常谈的继续孵化功能,所以这里拣选一些值得注意的新功能记录一下。

instanceOf的模式匹配应用于记录模式

形如以下形式的instanceof模式匹配在Java 16中被引入。

1
2
3
if (o instanceof String s) {
  System.out.println(s);
}

在这个简短的示例中,变量o的原始类型并不是String,可能仅是Object,但是通过instanceof操作符,变量o可以被确定为String的一个实例,那么这个完成类型确定以后的实例,就被交由变量s来引用了。这个模式取代了自谦旧式语法中,需要在if语句的条件判断中先试用instanceof操作符判断类型再在分支体里声明一个变量,并做一次类型转换了。

随着Java 17和Java 18中switch模式匹配功能的发展,更加大大的简化了对于数据的操作。Java 19在此基础上引入了一个记录模式的感念。一个记录模式由类型、可以与记录组件匹配的记录组件模式列表和可选标识符组成。其实说白了就还是上面那个简单的示例,只不过用在了更加复杂的记录类上。

例如:

1
2
3
4
5
6
7
// 如果有记录类
record Point(int x, int y) {}

// 那么在Java 19中可以这样从其中取得x和y的值
if (v instanceof Point(var a, var b)) {
  // 这里使用变量a和变量b
}

这在其他的语言里就可以被称为解构语法了。那么自然地,这个记录模式匹配也是支持泛型的,例如record Box<T>(T t) {},就可以使用b instanceof Box<Object>(String s)这样的表达式将其解构成String类型的值。

再继续延伸以后,这个表达式还可以使用在switch模式匹配上。

外部函数与内存API

外部函数与内存API在Java 17中进行了孵化,并在Java 19版本中达到了预览。

在没有外部函数和内存API的时候,我们需要通过sun.misc.Unsafe提供的功能来执行一些低级别、不安全的操作方法。从这个类的名字也能看出来,在大多数情况下这个功能还是不建议随意使用的。而从Java 1.1就开始支持的JNI调用,在实际使用中步骤复杂,并且会脱离JVM的语言安全机制控制。

所以在这种情况下,为了解决这些问题,Java引入了一套新的API,即外部函数和内存API(FFM API)。这套API主要定义了以下类和接口:

  • 分配外部内存:MemorySegmentMemoryAddressSegmentAllocator
  • 操作和访问结构化外部内存:MemoryLayoutVarHandle
  • 控制外部内存分配和释放:MemorySession
  • 调用外部函数:LinkerFunctionDescriptorSymbolLookup

例如可以这样在堆上存储四个字符串。

1
2
3
4
5
6
7
String[] strings = {"1", "2", "3", "4"};
SegmentAllocator allocator = implicitAllocator();
MemorySegment offHeap = allocator.allocateMemory(ValueLayout.ADDRESS, strings.length);
for (int i = 0; i < strings.length; i++) {
  MemorySegment cStr = allocator.allocateUtf8String(strings[i]);
  offHeap.setAtIndex(ValueLayout.ADDRESS, i, cStr);
}

虚拟线程

虚拟线程不是Java提出来的新东西,这种概念在其他的语言中早已被大量而普遍的使用,例如Go语言中的协程。

Java 19中引入的虚拟线程概念是由JDK实现的一个轻量级线程,多个虚拟线程共享一个系统线程。虚拟线程的使用可以避免传统线程上下文切换带来的额外资源耗费,可以简化高并发程序的编写和调试。

Java中在线程中运行一个任务的核心依旧是Runnable,但是任务启动已经发生了改变,例如可以使用Thread.ofVirtual()来创建一个虚拟线程,使用Thread.startVirtualThread(Runnable)来直接在虚拟线程中启动一个任务。而创建传统系统线程则是改为使用Thread.ofPlatform()来完成的。

虚拟线程的引入虽然使Java的线程管理API发生了一些变化,但其实际使用的核心功能API并未发生太大改变。

结构化并发

结构化并发在Java 19中是一个孵化功能,它出现的目的是为了简化多线程编程。结构化并发框不同线程中运行的多个任务视为一个工作单元,从而简化其中的错误处理并提高其可观察性和可靠性。

目前结构化并发提供的基本API是StructuredTaskScope,可以用来将一个任务拆分成多个并发子任务,子任务在自己的线程中执行,所有子任务执行结束后再继续执行主任务。

例如以下实例:

1
2
3
4
5
6
try (var scope = new StructuredTaskScope<Object>()) {
  Future<Integer> future1 = scope.fork(task1);
  Future<String> future2 = scope.fork(task2);
  scope.join();
  // 这里即可以使用future1和future2返回的内容。
}

索引标签
JVM
Java
Java 19
新特性
模式匹配
外部函数
虚拟线程
结构化并发