网站html下载,外包加工网手工活,附近2公里招临时工,珠海网站建设方案外包Java 21于2023年9月19日发布#xff0c;这是一个LTS#xff08;长期支持#xff09;版本#xff0c;到此为止#xff0c;目前有Java 8、Java 11、Java 17和Java 21这四个LTS版本。
Java 21此次推出了15个新特性#xff0c;本节就介绍其中重要的几个特性#xff1a; JEP…Java 21于2023年9月19日发布这是一个LTS长期支持版本到此为止目前有Java 8、Java 11、Java 17和Java 21这四个LTS版本。
Java 21此次推出了15个新特性本节就介绍其中重要的几个特性 JEP 430String Templates (Preview)字符串模板第一次预览 JEP 431Sequenced Collections 有序集合 JEP 439Generational ZGC 分代ZGC JEP 440Record Patterns Record模式转正 JEP 441Pattern Matching for switch switch的模式匹配转正 JEP 442Foreign Function Memory API (Third Preview) 外部函数和内存 API 第三次预览 JEP 444Virtual Threads 虚拟线程转正 JEP 445Unnamed Classes and Instance Main Methods (Preview) 未命名类和实例主要方法第一次预览 JEP 446Scoped Values (Preview) 作用域值第一次预览 JEP 448Vector API (Sixth Incubator)向量 API第六轮孵化 JEP 453Structured 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 cheapshow 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.htmlheadtitle\{title}/title/headbodyp\{text}/p/body/html;System.out.println(html);//html// head// titleMy Web Page/title// /head// body// pHello, world/p// /body///html
}
STR只是其中一个模板处理器本次一共推出了三个 STR将模板中的每个嵌入表达式替换为该表达式的字符串化值来执行字符串插值。 FMT类似于STR但是它还可以接受格式说明符这些格式说明符出现在嵌入式表达式的左边用来控制输出的样式。 RAW它会返回一个未处理的StringTemplate对象这个对象包含了模板中的文本和表达式信息。 FMT处理器就贴个官方的例子吧 RAW案例
public static void Str(){String name 橡皮人;StringTemplate stRAW.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 SequencedCollectionE extends CollectionE {//方法的功能见名知意不再赘述SequencedCollectionE 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) {ListString 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();//1ListString 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 440Record模式转正 记录模式由 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 441Switch的模式匹配转正 此功能最初由 JEP 406 Java 17 提出。 随后由 JEP 420 Java 18、427 Java 19 和 433 Java 20 改进。 在Java 21成为正式特性。 内容较多就不粘贴了可以参考Java 17、18、19、20对这一特性的介绍。
六、JEP 442外部函数和内存API第三次预览 外部函数和内存FFMAPI首先在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方法派生线程来执行任务FutureString user scope.fork(() - findUser());FutureInteger order scope.fork(() - fetchOrder());
scope.join(); // 将两个fork合并scope.throwIfFailed(); // ...出现异常抛异常
// 代表这两个fork都成功了组合它们的结果。return new Response(user.resultNow(), order.resultNow());}
}
End希望对大家有所帮助如果有纰漏或者更好的想法请您一定不要吝啬你的赐教。