Java 21新特性概述

Java 21于2023年9月19日发布,这是一个LTS(长期支持)版本,到此为止,目前有Java 8、Java 11、Java 17和Java 21这四个LTS版本。

Java 21此次推出了15个新特性,本节就介绍其中重要的几个特性:

  • JEP 430:String Templates (Preview)字符串模板(第一次预览)

  • JEP 431:Sequenced Collections 有序集合

  • JEP 439:Generational ZGC 分代ZGC

  • JEP 440:Record Patterns Record模式(转正)

  • JEP 441:Pattern Matching for switch switch的模式匹配(转正)

  • JEP 442:Foreign Function & Memory API (Third Preview) 外部函数和内存 API (第三次预览)

  • JEP 444:Virtual Threads 虚拟线程(转正)

  • JEP 445:Unnamed Classes and Instance Main Methods (Preview) 未命名类和实例主要方法(第一次预览)

  • JEP 446:Scoped Values (Preview) 作用域值(第一次预览)

  • JEP 448:Vector API (Sixth Incubator)向量 API(第六轮孵化)

  • JEP 453:Structured Concurrency (Preview)结构化并发(第一次预览)

更多内容读者可自行阅读:OpenJDK Java 21文档

一、JEP 430:字符串模板(第一次预览)

先卖个关子,我们平常作字符串拼接无非是以下几种方式:

public void concatStr(int x, int y) {String result="";//1、直接拼result= x + " plus " + y + " equals " + (x + y);//2、StringBuilderresult = new StringBuilder().append(x).append(" plus ").append(y).append(" equals ").append(x + y).toString();//3、format()result = String.format("%2$d plus %1$d equals %3$d", x, y, x + y);//4、MessageFormatMessageFormat mf = new MessageFormat("{0} plus {1} equals {2}");result = mf.format(result, x, y);
}

这或多或少都有缺点,比如难以阅读、复杂、冗长等。

Java 21引入的String Template就是为了解决这些问题的:

String Template提供了一种更简洁、更直观的方式来动态构建字符串的方式。通过"\ {}"占位符,我们就可以将变量的值嵌入到字符串中,在运行时会将占位符替换为实际的变量值。

talk is cheap,show me the code:

result= STR."\{x} plus \{y} equals \{x + y}";

是不是更直观、简洁、容易阅读了,我们再来看下它多行模板表达式的效果:

public static void main(String[] args) {String title = "My Web Page";String text  = "Hello, world";String html = STR."""<html><head><title>\{title}</title></head><body><p>\{text}</p></body></html>""";System.out.println(html);//<html>//  <head>//    <title>My Web Page</title>//  </head>//  <body>//    <p>Hello, world</p>//  </body>//</html>
}

STR只是其中一个模板处理器,本次一共推出了三个:

  • STR:将模板中的每个嵌入表达式替换为该表达式的(字符串化)值来执行字符串插值。

  • FMT:类似于STR,但是它还可以接受格式说明符,这些格式说明符出现在嵌入式表达式的左边,用来控制输出的样式。

  • RAW:它会返回一个未处理的StringTemplate对象,这个对象包含了模板中的文本和表达式信息。

FMT处理器就贴个官方的例子吧:

RAW案例:

public static void Str(){String name = "橡皮人";StringTemplate st=RAW."Hello, \{name}";String result = STR.process(st);//Hello, 橡皮人
}

除了这三个模板处理器,你还可以实现StringTemplate.Processor接口,并实现其process()方法即可自定义模板处理器。

二、JEP 431:有序集合

Java 21引入了一个新的集合接口Sequenced Collections,用于处理具有序列顺序的集合,目的是弥补现有集合接口中对顺序操作的支持不足。

ps:这里的有序指的是元素的存取顺序。

Sequenced Collections包含下面三个接口:

  • SequencedCollection

  • SequencedSet

  • SequencedMap

SequencedCollection继承自Collection接口,且List和Deque接口都继承了SequencedCollection:

public interface SequencedCollection<E> extends Collection<E> {//方法的功能见名知意,不再赘述SequencedCollection<E> reversed();default void addFirst(E e);default void addLast(E e);default E getFirst();default E getLast();default E removeFirst();default E removeLast();
}

举个例子:

public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("A"); //[A]list.addFirst("0");//[0,A]list.addLast("1");//[0,A,1]String first = list.getFirst();//0String last = list.getLast();//1List<String> reversed = list.reversed();//[1,A,0]
}

剩下两个就不做介绍了,也基本是这些方法,这里贴个官方文档中这三个集合接口的层次结构:

三、JEP 439:分代ZGC

  • ZGC 通过 JEP 333 集成到 Java 11 中,当时还是处于实验阶段。

  • 经过多个版本的迭代,ZGC在Java 15终于可以正式使用了,不过默认的垃圾回收器还是G1。

我们先回顾下Java 11时ZGC的特性:

  • 低停顿:GC停顿时间不超过10ms,通常是亚毫秒级别。

  • 高吞吐量:ZGC是一个并发垃圾回收器,意味着大部分垃圾收集工作都是在Java线程继续执行的同时完成的。

  • 兼容性:ZGC于现在Java应用程序完全兼容,但由于还处于实验阶段,目前只能在Linux/x64上使用。

  • 支持大堆:能处理8MB到16TB大小的堆,适用于大规模内存需要的应用程序。

  • 不分代回收:在垃圾回收时堆全量内存进行标记,但回收时仅针对分内存回收,优先回收垃圾比较多的页面。

在Java 17的HostSpot调优指南提到了weak generational hypothesis,指出年轻代的对象往往朝生夕死,而老年代的对象却长时间存在,因此收集年轻代对象所需的资源较少,并且回收的内存较多,而收集老年代则需要更多资源,回收的内存较少。因此,通过更频繁地收集年轻对象,可以提高使用ZGC的应用程序的性能。

因此,在Java 21提供了分代ZGC的功能,在未来版本中打算将非分代ZGC移除并把分代ZGC作为默认值。

目前使用分代ZGC需要以下参数启动:

java -XX:+UseZGC -XX:+ZGenerational

四、JEP 440:Record模式(转正)

  • 记录模式由 JEP 405 提议作为预览功能,并在 JDK 19 中提供。

  • JEP 432 再次预览并在 JDK 20 中提供。

  • 在Java 21成为正式特性。

本次除了一些细微的编辑更改外,自第二次预览以来的主要更改是删除了对出现在增强的 for 语句的标题中的记录模式的支持。此功能可能会在未来的 JEP 中重新提出。

也就是不再支持这种写法:

void dump(Point[] points){for (Point(var x, var y) : points) {System.out.println(x + " " + y);}
}

五、JEP 441:Switch的模式匹配(转正)

  • 此功能最初由 JEP 406 (Java 17) 提出。

  • 随后由 JEP 420 (Java 18)、427 (Java 19) 和 433 (Java 20) 改进。

  • 在Java 21成为正式特性。

内容较多,就不粘贴了,可以参考Java 17、18、19、20对这一特性的介绍。

六、JEP 442:外部函数和内存API(第三次预览)

  • 外部函数和内存(FFM)API首先在JDK 19中通过JEP 424预览。

  • 然后在JDK 20中通过JEP 434再次预览。

  • 此JEP提出第三次预览。

这次改动主要对相关API进行了调整。内容较多,就不粘贴了,详细内容请参考Java 19对这一特性的介绍。

七、JEP 444:虚拟线程(转正)

参考Java 21中虚拟线程是怎么回事。

八、JEP 445:未命名类和实例主要方法(第一次预览)

这个特性在Java 21没正式发布之前就被众多开发者吐槽为"最没用的特性",那这是怎么回事呢?下面我们看看。

这个特性主要简化了main方法的声明。对于 Java 初学者来说,这个 main 方法的声明引入了太多的 Java 语法概念,不利于初学者快速上手。

没有该特性之前的Hello World程序:

public class HelloWorld {public static void main(String[] args) {System.out.println("Hello World!");}
}

在Java 21增强了启动Java程序协议后,允许main方法不是static的,那也意味着类不需要是public,也不需要具有 String[]参数

class HelloWorld {void main() {System.out.println("Hello World!");}
}

再一次精简,未命名的类允许我们不定义类名

void main() {System.out.println("Hello World!");
}

九、JEP 446:作用域值(第一次预览)

  • 通过 JEP 429 在 JDK 20 中首次孵化。

  • 在 JDK 21 中,进行第一次预览,并无改动点。

作用域值允许在大型程序中的组件之间安全有效地共享数据,而无需求助于方法参数。它是ScopedValue 类型的变量。通常,它被声明为final static字段,因此可以很容易地从许多组件访问它。

像线程局部变量一样,作用域值(scoped value)在每个线程中都有多个实例。使用哪个具体的实例取决于哪个线程调用其方法。与线程局部变量不同,作用域值在写入后是不可变的,并且仅在线程执行的有限时间内可用。

下面的代码示例中使用了作用域值。一些代码会调用ScopedValue.where(…),提供一个作用域值和它想要绑定的对象。对run(…)的调用会绑定作用域值,提供一个特定于当前线程的版本,然后执行作为参数传递的lambda表达式。在run(…)方法执行期间,直接或间接从Lambda表达式调用的任何方法,都可以通过值get()方法读取作用域值。当run(…)方法完成后,绑定就会被销毁:

final static ScopedValue<...> V = ScopedValue.newInstance();// In some method
ScopedValue.where(V, <value>).run(() -> { ... V.get() ... call methods ... });// In a method called directly or indirectly from the lambda expression
... V.get() ...

这乍一看好像和ThreadLoacl差不多,但与ThreadLocal相比,它有以下几个优点:

  • 作用域值仅在run(...)方法的Runnable的生命周期内有效,并会在run方法执行完之后立即销毁(进行垃圾回收),而ThreadLocal会将value保存在内存中,直到线程被销毁(如果是线程池则永远不会销毁)或者调用remove方法,才能被垃圾回收。

  • 作用域值是不可变的,他只能通过重新绑定来重置新的值,这可以提高了代码的可读性,而ThreadLocal随时都可以使用set()更改(如果要溯源可能需要看好几处代码)。

  • 由StructuredTaskScope创建的子线程可以访问父线程的scoped值,而ThreadLocal也可以通过InheritableThreadLocal达到这个效果,不过它是通过创建副本的方式,这样内存占用相对来说也比较大。

  • 再一个比较重要的就是虚拟线程,由于虚拟线程是Thread的实例,所以也有线程局部变量的问题,我们知道虚拟线程可以大量创建,如果有数千或数百万个虚拟子线程时,访问父线程的scoped值(而不是通过创建副本的方式)可以节省大量内存。

十、JEP 448:向量API(第六轮孵化)

  • Vector API 最初由 JEP 338 提出,并作为孵化 API 集成到 JDK 16 中。

  • JEP 414(集成到 JDK 17 中)、JEP 417 (JDK 18)、JEP 426 (JDK 19) 和 JEP 438 (JDK 20) 。

  • 此JEP建议在JDK 21中进行第六轮孵化,与JDK 20相比,仅对相关API做了细微调整。

内容较多,就不粘贴了,可以参考Java 16、17、18、19、20对这一特性的介绍。

十一、JEP 453:结构化并发(第一次预览)

  • 结构化并发由 JEP 428 提出,并在 JDK 19 中作为孵化 API 提供。

  • 它在 JDK 20 中由 JEP 437 重新孵化。

  • 在JDK 21中进行第一次预览,与JDK 20相比,唯一的变化是StructuredTaskScope的fork()方法的返回值,由Future变为SubTask。

以下内容摘自Java 19对该特性的介绍:

Java 19引入了结构化并发,一种多线程编程方式,目的是为了通过结构化并发API来简化多线程编程,目前处于孵化阶段。

结构化并发 API 的主要类是 StructuredTaskScope。这个类允许开发者将一个任务组织成一组并发子任务,并将它们作为一个整体进行协调。子任务在各自的线程中执行,通过分别分叉(fork)它们,然后作为一个整体进行合并(join),并且可能作为一个整体进行取消。子任务的成功结果或异常由父任务进行聚合和处理。StructuredTaskScope 将子任务或分叉的生命周期限制在一个明确的词法范围内,在这个范围内,任务与其子任务的所有交互——包括分叉、合并、取消、处理错误和结果组合——都发生在此范围内。

StructuredTaskScope一般工作流程如下:

  • 创建一个作用域(scope)。创建作用域的线程是它的所有者。

  • 在作用域中分叉(fork)并发子任务。

  • 作用域中的任何分叉或作用域的所有者都可以调用作用域的 shutdown() 方法来请求取消所有剩余的子任务。

  • 作用域的所有者作为一个整体加入作用域,即所有分叉。所有者可以调用作用域的 join() 方法,该方法会阻塞直到所有分叉要么完成(成功或失败),要么通过 shutdown() 被取消。或者,所有者可以调用作用域的 joinUntil(java.time.Instant) 方法,该方法接受一个截止时间。

  • 加入后,处理任何分叉中的错误并处理它们的结果。

  • 关闭作用域,通常通过 try-with-resources 隐式完成。这会关闭作用域并等待任何滞后的分叉完成。

这是官方给的一个示例:

Response handle() throws ExecutionException, InterruptedException {try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {//使用fork方法派生线程来执行任务Future<String> user  = scope.fork(() -> findUser());Future<Integer> order = scope.fork(() -> fetchOrder());
​scope.join();           // 将两个fork合并scope.throwIfFailed();  // ...出现异常(抛异常)
​// 代表这两个fork都成功了,组合它们的结果。return new Response(user.resultNow(), order.resultNow());}
}

End:希望对大家有所帮助,如果有纰漏或者更好的想法,请您一定不要吝啬你的赐教🙋。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/882979.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu20.04安装ROS2教程

Ubuntu20.04安装ROS2教程 ROS 2 安装指南支持的ROS 2 版本设置语言环境&#xff08;Set locale&#xff09;设置源&#xff08;Setup Sources&#xff09;设置密钥安装 ROS 2 包&#xff08;Install ROS 2 packages&#xff09;环境设置&#xff08;Environment setup&#xff…

java--反射(reflection)

一、反射机制 Java Reflection &#xff08;1&#xff09;反射机制允许程序在执行期借助 Reflection API 取得任何类的内部信息&#xff08;比如成员变量、构造器、成员方法等等&#xff09;&#xff0c;并能操作对象的属性及方法。反射在设计模式和框架底层都会用到。&#x…

时间序列预测(九)——门控循环单元网络(GRU)

目录 一、GRU结构 二、GRU核心思想 1、更新门&#xff08;Update Gate&#xff09;&#xff1a;决定了当前时刻隐藏状态中旧状态和新候选状态的混合比例。 2、重置门&#xff08;Reset Gate&#xff09;&#xff1a;用于控制前一时刻隐藏状态对当前候选隐藏状态的影响程度。…

Java项目-基于springboot框架的智慧外贸系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…

小新学习K8s第一天之K8s基础概念

目录 一、Kubernetes&#xff08;K8s&#xff09;概述 1.1、什么是K8s 1.2、K8s的作用 1.3、K8s的功能 二、K8s的特性 2.1、弹性伸缩 2.2、自我修复 2.3、服务发现和负载均衡 2.4、自动发布&#xff08;默认滚动发布模式&#xff09;和回滚 2.5、集中化配置管理和密钥…

高效改进!防止DataX从HDFS导入关系型数据库丢数据

高效改进&#xff01;防止DataX从HDFS导入关系型数据库丢数据 针对DataX在从HDFS导入数据到关系型数据库过程中的数据丢失问题&#xff0c;优化了分片处理代码。改动包括将之前单一分片处理逻辑重构为循环处理所有分片&#xff0c;确保了每个分片数据都得到全面读取和传输&…

Python 实现 excel 数据过滤

一、场景分析 假设有如下一份 excel 数据 shop.xlsx, 写一段 python 程序&#xff0c;实现对于车牌的分组数据过滤。 并以车牌为文件名&#xff0c;把店名输出到 车牌.txt 文件中。 比如 闽A.txt 文件内容为&#xff1a; 小林书店福州店1 小林书店福州店2 二、依赖安装 程序依…

TBWeb正式稳定版V3.4.0+AI+MJ绘画+免授权无后门+详细安装教程

TBWeb正式稳定版V3.4.0AIMJ绘画免授权无后门详细安装教程&#xff1b; 运行环境 Nginx1.22 PHP5.7 MySQL7.4 Redis7.0 Node.js&#xff08;16.19.1&#xff09; PM2管理器5.6 TBWeb系统是基于 NineAI 二开的可商业化 TB Web 应用&#xff08;免授权&#xff0c;无后门&a…

【隐私计算】隐语HEU同态加密算法解读

HEU: 一个高性能的同态加密算法库&#xff0c;提供了多种 PHE 算法&#xff0c; 包括ZPaillier、FPaillier、IPCL、Damgard Jurik、DGK、OU、EC ElGamal 以及基于FPGA和GPU硬件加速版本的Paillier版本。 本文我们会基于GPU运行HEU Docker容器&#xff0c;编译打包GPaillier并测…

算法的学习笔记—两个链表的第一个公共结点(牛客JZ52)

&#x1f600;前言 在链表问题中&#xff0c;寻找两个链表的第一个公共结点是一个经典问题。这个问题的本质是在两个单链表中找到它们的相交点&#xff0c;或者说它们开始共享相同节点的地方。本文将详细讲解这个问题的解题思路&#xff0c;并提供一种高效的解决方法。 &#x…

蓝牙资讯|iOS 18.1 正式版下周推送,AirPods Pro 2耳机将带来助听器功能

苹果公司宣布将在下周发布 iOS 18.1 正式版&#xff0c;同时确认该更新将为 AirPods Pro 2 耳机带来新增“临床级”助听器功能。在启用功能后&#xff0c;用户首先需要使用 AirPods 和 iPhone 进行简短的听力测试&#xff0c;如果检测到听力损失&#xff0c;系统将创建一项“个…

docker run 命令解析

docker run 命令解析 docker run 命令用于从给定的镜像启动一个新的容器。这个命令可以包含许多选项&#xff0c;下面是一些常用的选项&#xff1a; -d&#xff1a;后台运行容器&#xff0c;并返回容器ID&#xff1b;-i&#xff1a;以交互模式运行容器&#xff0c;通常与 -t …

【C++】string类 (模拟实现详解 下)

我们接着上一篇【C】string类 &#xff08;模拟实现详解 上&#xff09;-CSDN博客继续对string模拟实现。从这篇内容开始&#xff0c;string相关函数的实现就要声明和定义分离了。 1.reserve、push_back和append 在string.h的string类里进行函数的声明。 void reserve(size_…

JVM(HotSpot):GC之垃圾回收器的分类

文章目录 前言一、串行二、吞吐量优先三、响应时间优先四、常见垃圾回收器使用组合 前言 上一篇&#xff0c;我们学习了分代回收机制 它的主要内容是对JVM内存的一个划分&#xff0c;以及垃圾回收器工作时&#xff0c;区域运作顺序的一个规定。 所以&#xff0c;它是一个规范。…

Spring Boot论坛网站:开发、部署与管理

3系统分析 3.1可行性分析 通过对本论坛网站实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本论坛网站采用SSM框架&#xff0c;JAVA作为开发语言&#xff0c;是…

智慧楼宇平台,构筑未来智慧城市的基石

随着城市化进程的加速&#xff0c;城市面临着前所未有的挑战。人口密度的增加、资源的紧张、环境的恶化以及对高效能源管理的需求&#xff0c;都在推动着我们寻找更加智能、可持续的城市解决方案。智慧楼宇作为智慧城市建设的重要组成部分&#xff0c;正逐渐成为推动城市可持续…

MATLAB电化学特性评估石墨和锂电

&#x1f3af;要点 模拟对比石墨电池的放电电压曲线与实验数据定性差异。对比双箔、多相多孔电极理论和锂电有限体积模型实现。通过孔隙电极理论模型了解粗粒平均质量和电荷传输以及孔隙率的表征意义。锂电中锂离子正向和逆向反应速率与驱动力的指数以及电解质和电极表面的锂浓…

Docker 部署 EMQX 一分钟极速部署

部署 EMQX ( Docker ) [Step 1] : 拉取 EMQX 镜像 docker pull emqx/emqx:latest[Step 2] : 创建目录 ➡️ 创建容器 ➡️ 拷贝文件 ➡️ 授权文件 ➡️ 删除容器 # 创建目录 mkdir -p /data/emqx/{etc,data,log}# 创建容器 docker run -d --name emqx -p 1883:1883 -p 1808…

「Qt Widget中文示例指南」如何实现半透明背景?

Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写&#xff0c;所有平台无差别运行&#xff0c;更提供了几乎所有开发过程中需要用到的工具。如今&#xff0c;Qt已被运用于超过70个行业、数千家企业&#xff0c;支持数百万设备及应用。 本文将为大家展示如…

《Linux从小白到高手》综合应用篇:深入理解Linux常用关键内核参数及其调优

1. 题记 有关Linux关键内核参数的调整&#xff0c;我前面的调优文章其实就有涉及到&#xff0c;只是比较零散&#xff0c;本篇集中深入介绍Linux常用关键内核参数及其调优&#xff0c;Linux调优80%以上都涉及到内核的这些参数的调整。 2. 文件系统相关参数 fs.file-max 参数…