余晖落尽暮晚霞,黄昏迟暮远山寻
本站
当前位置:网站首页 > 编程知识 > 正文

Java19的新特性(java19和17的区别)

xiyangw 2023-01-11 18:55 3030 浏览 0 评论

Java语言特性系列

Java5的新特性Java6的新特性Java7的新特性Java8的新特性Java9的新特性Java10的新特性Java11的新特性Java12的新特性Java13的新特性Java14的新特性Java15的新特性Java16的新特性Java17的新特性Java18的新特性Java19的新特性Java20的新特性

本文主要讲述一下Java19的新特性

版本号

java -version
openjdk version "19" 2022-09-20
OpenJDK Runtime Environment (build 19+36-2238)
OpenJDK 64-Bit Server VM (build 19+36-2238, mixed mode, sharing)

从version信息可以看出是build 19+36

特性列表

JEP 405: Record Patterns (Preview)

instanceof的模式匹配在JDK14作为preview,在JDK15作为第二轮的preview,在JDK16JEP 394: Pattern Matching for instanceof转正 switch模式匹配在JDK17的JEP 406: Pattern Matching for switch (Preview)引入作为preview版本,在JDK18的JEP 420: Pattern Matching for switch (Second Preview)作为第二轮的preview

针对record类型,引入instance of可以这么写

record Point(int x, int y) {}

static void printSum(Object o) {
    if (o instanceof Point p) {
        int x = p.x();
        int y = p.y();
        System.out.println(x+y);
    }
}

现在可以这么写

record Point(int x, int y) {}

void printSum(Object o) {
    if (o instanceof Point(int x, int y)) {
        System.out.println(x+y);
    }
}

比较复杂的例子:

record Point(int x, int y) {}
enum Color { RED, GREEN, BLUE }
record ColoredPoint(Point p, Color c) {}
record Rectangle(ColoredPoint upperLeft, ColoredPoint lowerRight) {}

Rectangle r = new Rectangle(new ColoredPoint(new Point(x1, y1), c1), 
                            new ColoredPoint(new Point(x2, y2), c2));

static void printXCoordOfUpperLeftPointWithPatterns(Rectangle r) {
    if (r instanceof Rectangle(ColoredPoint(Point(var x, var y), var c),
                               var lr)) {
        System.out.println("Upper-left corner: " + x);
    }
}

如果是泛型record的话:

record Box<T>(T t) {}

static void test1(Box<Object> bo) {
    if (bo instanceof Box<Object>(String s)) {
        System.out.println("String " + s);
    }
}
static void test2(Box<Object> bo) {
    if (bo instanceof Box<String>(var s)) {
        System.out.println("String " + s);
    }
}

JEP 422: Linux/RISC-V Port

RISC-V是一个基于精简指令集(RISC)原则的开源指令集架构(ISA),这个JEP则移植JDK到RISC-V上

JEP 424: Foreign Function & Memory API (Preview)

Foreign Function & Memory (FFM) API包含了两个incubating API JDK14的JEP 370: Foreign-Memory Access API (Incubator)引入了Foreign-Memory Access API作为incubator JDK15的JEP 383: Foreign-Memory Access API (Second Incubator)Foreign-Memory Access API作为第二轮incubator JDK16的JEP 393: Foreign-Memory Access API (Third Incubator)作为第三轮,它引入了Foreign Linker API (JEP 389) FFM API在JDK 17的JEP 412: Foreign Function & Memory API (Incubator)作为incubator引入 FFM API在JDK 18的JEP 419: Foreign Function & Memory API (Second Incubator)作为第二轮incubator JDK19的这个JEP则将FFM API作为preview API

使用示例

// 1. Find foreign function on the C library path
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
MethodHandle radixSort = linker.downcallHandle(
                             stdlib.lookup("radixsort"), ...);
// 2. Allocate on-heap memory to store four strings
String[] javaStrings   = { "mouse", "cat", "dog", "car" };
// 3. Allocate off-heap memory to store four pointers
SegmentAllocator allocator = SegmentAllocator.implicitAllocator();
MemorySegment offHeap  = allocator.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
// 4. Copy the strings from on-heap to off-heap
for (int i = 0; i < javaStrings.length; i++) {
    // Allocate a string off-heap, then store a pointer to it
    MemorySegment cString = allocator.allocateUtf8String(javaStrings[i]);
    offHeap.setAtIndex(ValueLayout.ADDRESS, i, cString);
}
// 5. Sort the off-heap data by calling the foreign function
radixSort.invoke(offHeap, javaStrings.length, MemoryAddress.NULL, '\0');
// 6. Copy the (reordered) strings from off-heap to on-heap
for (int i = 0; i < javaStrings.length; i++) {
    MemoryAddress cStringPtr = offHeap.getAtIndex(ValueLayout.ADDRESS, i);
    javaStrings[i] = cStringPtr.getUtf8String(0);
}
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"});  // true

JEP 425: Virtual Threads (Preview)

虚拟线程应该是JDK19最重磅的特性,首次集成进来即为preview的API 虚拟线程是由JDK提供的用户态线程,类似golang的goroutine,erlang的processes 虚拟线程采用的是M:N的调度模式,即M数量的虚拟线程运行在N个Thread上,使用的是ForkJoinPool以FIFO模式来进行调度,N默认是为Runtime.availableProcessors(),可以通过 jdk.virtualThreadScheduler.parallelism来修改

使用示例

try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
    IntStream.range(0, 10_000).forEach(i -> {
        executor.submit(() -> {
            Thread.sleep(Duration.ofSeconds(1));
            return i;
        });
    });
}  // executor.close() is called implicitly, and waits

如上使用了少数几个OS线程来运行10000个虚拟线程 虚拟线程在超过上千个非CPU密集并发任务场景可以显著提升系统的吞吐率

void handle(Request request, Response response) {
    var url1 = ...
    var url2 = ...

    try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
        var future1 = executor.submit(() -> fetchURL(url1));
        var future2 = executor.submit(() -> fetchURL(url2));
        response.send(future1.get() + future2.get());
    } catch (ExecutionException | InterruptedException e) {
        response.fail(e);
    }
}

String fetchURL(URL url) throws IOException {
    try (var in = url.openStream()) {
        return new String(in.readAllBytes(), StandardCharsets.UTF_8);
    }
}

像这种场景虽然是block的代码,但是因为引入的是虚拟线程,系统可以很好地伸缩;当虚拟线程block在IO或者其他操作( BlockingQueue.take())时,虚拟线程会从Thread unmount,当操作完成才重新mount上继续执行。不过有些操作不会unmount虚拟线程,会一同thread和底层的OS线程一起block住(比如进入synchronized代码块/方法,比如执行一个native方法或者foreign function)。 虚拟线程开销不大,因而不需要使用池化技术 使用 jcmd<pid>Thread.dump_to_file-format=json<file>可以以json格式来dump虚拟线程,实例如下

Thread.Builder, Thread.ofVirtual(), Thread.ofPlatform() 可以用来创建虚拟线程或者是平台线程,比如

Thread thread = Thread.ofVirtual().name("duke").unstarted(runnable);

Thread.startVirtualThread(Runnable)等同于创建和启动虚拟线程 Thread.threadId() 作为final方法会返回线程标识,而非final的Thread.getId()则被废弃 Thread.getAllStackTraces()现在返回的是平台线程而非所有线程

JEP 426:Vector API (Fourth Incubator)

JDK16引入了JEP 338: Vector API (Incubator)提供了jdk.incubator.vector来用于矢量计算 JDK17进行改进并作为第二轮的incubatorJEP 414: Vector API (Second Incubator) JDK18的JEP 417: Vector API (Third Incubator)进行改进并作为第三轮的incubator,而JDK19则作为第四轮的incubator

JEP 427: Pattern Matching for switch (Third Preview)

instanceof的模式匹配在JDK14作为preview,在JDK15作为第二轮的preview,在JDK16转正 JDK17引入JEP 406: Pattern Matching for switch (Preview) JDK18的JEP 420: Pattern Matching for switch (Second Preview)则作为第二轮的preview,JDK19作为第三轮preview

JEP 428: Structured Concurrency (Incubator)

结构化并发也是JDK19的一个重要特性。JDK5引入的ExecutorService可以用于并行处理任务,比如

Response handle() throws ExecutionException, InterruptedException {
    Future<String>  user  = esvc.submit(() -> findUser());
    Future<Integer> order = esvc.submit(() -> fetchOrder());
    String theUser  = user.get();   // Join findUser
    int    theOrder = order.get();  // Join fetchOrder
    return new Response(theUser, theOrder);
}

但是当findUser抛出异常时,fetchOrder还是会在自己的线程继续运行,或者findUser需要运行很长时间,而当fetchOrder异常时,整个handle方法还是需要浪费时间等待findUser执行完,它阻塞在user.get()。为了更好地处理这种在异常场景下取消其他子任务,引入结构化并发来解决此问题,其主要是StructuredTaskScope这个类,它可以fork子任务,然后一起join或者一起cancel。

Response handle() throws ExecutionException, InterruptedException {
    try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
        Future<String>  user  = scope.fork(() -> findUser());
        Future<Integer> order = scope.fork(() -> fetchOrder());

        scope.join();           // Join both forks
        scope.throwIfFailed();  // ... and propagate errors

        // Here, both forks have succeeded, so compose their results
        return new Response(user.resultNow(), order.resultNow());
    }
}

如果其中一个子任务失败了,则会取消另外一个在运行的任务。在scope.join()之后,可以使用resultNow()或者exceptionNow()来获取结果

细项解读

上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 19 Release Notes,这里举几个例子。

添加项

  • System Properties for System.out and System.err (JDK-8283620)

新增stdout.encoding这两个系统属性stderr.encoding

  • Support Unicode 14.0 (JDK-8268081)

新增支持unicode 14.0版本

  • Additional Date-Time Formats (JDK-8176706)

以前java.time.format.DateTimeFormatter/DateTimeFormatterBuilder只支持FormatStyle.FULL/LONG/MEDIUM/SHORT这四种,现在可以自定义,比如 DateTimeFormatter.ofLocalizedPattern("yMMM")

  • Automatic Generation of the CDS Archive (JDK-8261455)

新增 -XX:+AutoCreateSharedArchive参数可以自动创建CDS archive,比如 java-XX:+AutoCreateSharedArchive-XX:SharedArchiveFile=app.jsa-cp app.jarApp

移除项

  • Remove Finalizer Implementation in SSLSocketImpl (JDK-8212136)

移除SSLSocket的finalizer实现

  • Removal of Diagnostic Flag GCParallelVerificationEnabled (JDK-8286304)

移除GCParallelVerificationEnabled参数

废弃项

完整列表见Java SE 19 deprecated-list

  • java.lang.ThreadGroup Is degraded (JDK-8284161)

ThreadGroup不能再被显示destroy了,它现在不再与其subgroup保持强引用

  • Deprecation of Locale Class Constructors (JDK-8282819)

Locale的构造器被废弃了,可用Locale.of()这个工厂方法替代

已知问题

  • ForkJoinPool and ThreadPoolExecutor do not use Thread::start to Start Worker Threads (JDK-8284161)

ForkJoinPool及ThreadPoolExecutor在这个版本不再使用`Thread::start来启动线程了,因而那些override无参start的工作线程可能会受影响,不过ForkJoinWorkerThread.onStart()不受影响

  • InflaterInputStream.read Throws EOFException (JDK-8292327)

InflaterInputStream在这个版本可能抛出EOFException

  • G1 Remembered set memory footprint regression after JDK-8286115 (JDK-8292654)

JDK-8286115这个变动了G1的RSet的ergonomic size,会造成本地内存使用增加,可以通过增加G1RemSetArrayOfCardsEntries值来缓解,比如

-XX:+UnlockExperimentalVMOptions -XX:G1RemSetArrayOfCardsEntries=128

其他事项

  • JNI GetVersion Returns JNIVERSION19 (JDK-8286176)

GetVersion这个jni方法返回JNIVERSION19

  • Double.toString(double) and Float.toString(float) may Return Slightly Different Results (JDK-4511638)

Double.toString(2e23), 现在会返回"2.0E23", 而之前的版本会返回"1.9999999999999998E23"

  • Make HttpURLConnection Default Keep Alive Timeout Configurable (JDK-8278067)

新增了http.keepAlive.time.server及http.keepAlive.time.proxy系统属性可以用于修改默认的Keep Alive Timeout

  • JVM TI Changes to Support Virtual Threads (JDK-8284161)

The JVM Tool Interface (JVM TI)已经更新,现可支持虚拟线程

  • -Xss may be Rounded up to a Multiple of the System Page Size (JDK-8236569)

实际的java线程堆栈大小可能与-Xss命令行选项指定的值不同;它可能四舍五入为系统所需的页面大小的倍数。

小结

Java18主要有如下几个特性

  • JEP 405: Record Patterns (Preview)
  • JEP 422: Linux/RISC-V Port
  • JEP 424: Foreign Function & Memory API (Preview)
  • JEP 425: Virtual Threads (Preview)
  • JEP 426: Vector API (Fourth Incubator)
  • JEP 427: Pattern Matching for switch (Third Preview)
  • JEP 428: Structured Concurrency (Incubator)

doc

  • JDK 19 Features
  • JDK 19 Release Notes
  • Consolidated JDK 19 Release Notes
  • Java SE 19 deprecated-list
  • The Arrival of Java 19
  • JDK 19 G1/Parallel/Serial GC changes
  • Java 19 Delivers Features for Projects Loom, Panama and Amber
  • JDK 19 and JDK 20: What We Know So Far

相关推荐

高效删除文件名中的指定内容,祛除烦恼

如何快速批量删除文件名中的指定字符?在电脑整理文件时,我们常常需要进行批量重命名操作。如果文件名中含有不必要或重复的字符,这将影响文件的识别和查找。因此,删除这些文字或字符是非常必要且有效的。本文将分...

你的手机是不是经常提示存储空间不足?Python帮你清理重复文件

  最近我的手机经常提示存储空间不足,主要是微信和QQ群里接收的文件太多了,平时也没怎么整理。我把这些文件从手机里拷出来,打算整理一下,把该删的文件都删掉,把要备份的文件分门别类存到电脑或网盘上。我突...

从零开始打造云端AI管理调度平台(四)如何设计主页_1

最近闲来无事,想着把自己工作正在做的一个项目做一个简单的分享与实战教程,该项目不困难但是由于涉及要素过多所以比较复杂。所以这里分享出来也是为了帮助新手小白能在实战当中快速了解python知识。主要内容...

「万能Python」-17-标准库OS_python2.7标准库

Python的库是指预先编写好的代码集合,可以用来处理特定的任务或实现特定的功能。Python的标准库提供了许多常用的标准库,无需安装引入使用。Python3的标准库提供了许多常用的功能,包括...

十多行代码生成原帖和临写对照图_几十行代码可以申请软著吗

介绍这个小工具把原帖和临写分解成多列对照的形式。输入原帖图片,和输入临写图片,生成对照图片。使用说明运行compare.py文件,输入参数为:原帖图片文件名,临写图片文件名,列数。python3co...

Python合集之目录操作(四)_python之文件操作大全

1.删除目录删除目录可以通过os模块提供的rmdir()函数实现。通过rmdir()函数删除目录时,只有当要删除的目录为空时才起作用。os.rmdir(path)path为要删除的目录,可以使用绝对路...

excel办公自动化,自动合并excel表格

平时时收到不同人反馈的excel表格,需要将其合并在一个excel中,每个excel打开复制粘贴会很慢,如下脚本可一键合并所有的exceldefauto_merge():try:print('...

批量打开一个文件夹下面所有的excel表格

如果现在有一个文件夹,名称叫做“练习表格”,路径名是'C:\Users\123\Desktop\练习表格',现在的要求是打开这个文件下面所有的excel表格,后缀名字为“xlsx”,我...

500行代码,教你用python写个微信飞机大战

这几天在重温微信小游戏的飞机大战,玩着玩着就在思考人生了,这飞机大战怎么就可以做的那么好,操作简单,简单上手。帮助蹲厕族、YP族、饭圈女孩在无聊之余可以有一样东西让他们振作起来!让他们的左手/右手...

python 日志写入_python日志文件写入

1.第一步,新建日志文件路径,如下图:2.日志模块封装,代码如下:importlogging,oslogs_path=os.path.join(os.path.dirname(__file...

Python os.path模块使用指南:轻松处理文件路径

前言在Python编程中,文件和目录的操作是非常重要的一部分。为了方便用户进行文件和目录的操作,Python标准库提供了os模块。其中,os.path子模块提供了一些处理文件路径的函数和方法。本文主要...

Python中获取当前路径之pathilb和os的区别

20230114星期六:1,直接在py脚本中,执行,没有区别;2,打包成exe文件以后,在本机执行,有区别,这时,不能使用os.path.dirname(__file__),只能使用pathlib.P...

Python(办公自动化编程系列)学习笔记1

1、获得当前程序工作目录importos#os.getcwd()函数可以取得当前工作路径的字符串print(os.getcwd())运行结果2、获得程序文件夹相对路径#相对路径都用/表示#../...

文件路径名Pathnames的操作_路径和文件名是什么意思

1.现象问题使用路径名来获取文件名,目录名,绝对路径等等2.原因分析无3.问题解决使用os.path模块中的函数来操作路径名importos.path#查看标准化的绝对路径print...

关于《Python入门:os常用函数》中复制文件(夹)函数从简到繁

基本考虑练习os模块及file读写操作:将给定的源路径的文件(夹)复制到目标路径简单实现#文件到文件的复制path_src='E:\src.txt'path_tar='D...

取消回复欢迎 发表评论: