Java SE 19 新增特性

作者:Grey

原文地址:

博客园:Java SE 19 新增特性

CSDN:Java SE 19 新增特性

源码

源仓库: Github:java_new_features

镜像仓库: GitCode:java_new_features

HashMap 新的构造方法

Java SE 19,构造哈希表的时候,由于有扩容因子 0.75 的设置,所以如果要开辟一个 120 空间的哈希表,需要如下定义

Map<Integer,Integer> map1 = new HashMap<>(160);

Java SE 19 中,HashMap 有了新的构造方法,可以用 newHashMap 直接指定具体大小,不需要提前做换算。

这个用法类似 Guava 的集合构造方式。

如上例,可以使用

Map<Integer, Integer> map2 = HashMap.newHashMap(120);

代码如下

import java.util.*;
public class NewHashMapMethodTest {
public static void main(String[] arg) {
// jdk 19之前
// 由于有 扩容因子 0.75 的设置,所以如果要开辟一个120的哈希表,需要如下定义
Map<Integer,Integer> map1 = new HashMap<>(160);
for (int i = 0; i < 10; i++) {
map1.put(i,i);
}
System.out.println(map1);
// jdk 19及以后
// 可以用newHashMap直接指定具体大小,不需要提前做换算
Map<Integer, Integer> map2 = HashMap.newHashMap(120);
for (int i = 0; i < 10; i++) {
map2.put(i,i);
}
System.out.println(map2);
}
}

switch 类型匹配增强(第三次预览)

首次引入这个功能是在Java SE 17

switch (obj) {
case String s && s.length() > 5 -> System.out.println(s.toUpperCase())。
...
}

我们可以在 switch 语句中检查一个对象是否属于某个特定的类,以及它是否有额外的特征(比如在例子中:长于五个字符)。

在 Java SE 19 中,我们必须使用新的关键字 when 来代替 &&

完整代码如下

package git.snippets.jdk19;

/**
* switch 增强 第三次预览
* 需要增加 --enable-preview参数
*
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/22
* @since 19
*/
public class SwitchEnhancedTest {
public static void main(String[] args) {
checkObjSince19("hello world");
} public static void checkObjSince19(Object when) {
// when 是一个所谓的 "上下文关键字",因此只在一个 case 标签中具有意义。如果你的代码中有名称为 "when "的变量或方法,你不需要改变它们。
switch (when) {
case String s when s.length() > 5 -> System.out.println(s.toUpperCase());
case String s -> System.out.println(s.toLowerCase());
case Integer i -> System.out.println(i * i);
default -> {
}
}
}
}

when 是一个所谓的 "上下文关键字",因此只在一个 case 标签中具有意义。如果你的代码中有名称为 "when "的变量或方法,你不需要改变它们。

record 的匹配增强(预览功能)

switch 和 instanceof 的增强匹配(Java SE 16 新增特性)功能现在可以用于 record,示例代码如下

package git.snippets.jdk19;

/**
* record 模式匹配增强
* 需要增加 --enable-preview参数
*
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/22
* @since 19
*/
public class RecordTest {
public static void main(String[] args) {
Points points = new Points(1, 2);
Line line = new Line(new Points(1, 2), new Points(3, 4));
printPoints(points);
printLine(line);
} private static void printPoints(Object object) {
if (object instanceof Points(int x,int y)) {
System.out.println("jdk 19 object is a position, x = " + x + ", y = " + y);
}
if (object instanceof Points points) {
System.out.println("pre jdk 19 object is a position, x = " + points.x()
+ ", y = " + points.y());
}
switch (object) {
case Points position -> System.out.println("pre jdk 19 object is a position, x = " + position.x()
+ ", y = " + position.y());
default -> throw new IllegalStateException("Unexpected value: " + object);
}
switch (object) {
case Points(int x,int y) -> System.out.println(" jdk 19 object is a position, x = " + x
+ ", y = " + y);
default -> throw new IllegalStateException("Unexpected value: " + object);
} } public static void printLine(Object object) {
if (object instanceof Line(Points(int x1,int y1),Points(int x2,int y2))) {
System.out.println("object is a path, x1 = " + x1 + ", y1 = " + y1
+ ", x2 = " + x2 + ", y2 = " + y2);
}
switch (object) {
case Line(Points(int x1,int y1),Points(int x2,int y2)) ->
System.out.println("object is a path, x1 = " + x1 + ", y1 = " + y1
+ ", x2 = " + x2 + ", y2 = " + y2);
// other cases ...
default -> throw new IllegalStateException("Unexpected value: " + object);
}
} } record Points(int x, int y) {
} record Line(Points from, Points to) {
}

虚拟线程(预览功能)

虚拟线程在Project Loom中已经开发了好几年,到目前为止只能用自编译的JDK进行测试。

具体可以查看这篇文章:Virtual Threads in Java (Project Loom)

Foreign Function 和 Memory API (预览功能)

Project Panama中,取代繁琐、易出错、速度慢的 Java 本地接口(JNI)的工作已经进行了很长时间。

在 Java 14 和 Java 16 中已经引入了 "外来内存访问 API "和 "外来链接器 API"--最初都是单独处于孵化阶段。在 Java 17 中,这些 API 被合并为 "Foreign Function & Memory API"(FFM API),直到 Java 18,它一直处于孵化阶段。

在 Java 19 中,JDK Enhancement Proposal 424最终将新的 API 提升到了预览阶段,

FFM API 可以直接从 Java 访问本地内存(即 Java 堆外的内存)和访问本地代码(如 C 库)。

下面是一个简单的例子,它在堆外内存中存储一个字符串,并对其调用 C 语言标准库的 "strlen "函数。

package git.snippets.jdk19;

import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.Linker;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
import java.lang.invoke.MethodHandle; import static java.lang.foreign.SegmentAllocator.implicitAllocator;
import static java.lang.foreign.ValueLayout.ADDRESS;
import static java.lang.foreign.ValueLayout.JAVA_LONG; /**
* FFM API
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/22
* @since 19
*/
public class FFMTest {
public static void main(String[] args) throws Throwable {
// 1. Get a lookup object for commonly used libraries
SymbolLookup stdlib = Linker.nativeLinker().defaultLookup(); // 2. Get a handle to the "strlen" function in the C standard library
MethodHandle strlen = Linker.nativeLinker().downcallHandle(
stdlib.lookup("strlen").orElseThrow(),
FunctionDescriptor.of(JAVA_LONG, ADDRESS)); // 3. Convert Java String to C string and store it in off-heap memory
MemorySegment str = implicitAllocator().allocateUtf8String("Happy Coding!"); // 4. Invoke the foreign function
long len = (long) strlen.invoke(str); System.out.println("len = " + len);
}
}

结构化并发(孵化器)

如果一个任务由不同的子任务组成,可以并行完成(例如,从数据库访问数据、调用远程 API 和加载文件),我们可以使用 Java 多线程的一些工具类来完成。

例如:

    private final ExecutorService executor = Executors.newCachedThreadPool();

    // jdk 19 之前
public Invoice createInvoice(int orderId, int customerId, String language) throws ExecutionException, InterruptedException {
Future<Order> orderFuture = executor.submit(() -> loadOrderFromOrderService(orderId)); Future<Customer> customerFuture = executor.submit(() -> loadCustomerFromDatabase(customerId)); Future<String> invoiceTemplateFuture = executor.submit(() -> loadInvoiceTemplateFromFile(language)); Order order = orderFuture.get();
Customer customer = customerFuture.get();
String invoiceTemplate = invoiceTemplateFuture.get(); return Invoice.generate(order, customer, invoiceTemplate);
}

但是:

如果一个子任务发生错误--我们如何取消其他子任务?

如果某个子任务不需要了,我们如何取消这个子任务呢?

这两种情况都可以,但需要相当复杂和难以维护的代码。

而如果我们想对这种类型的并发代码进行调试也非常麻烦。

JDK Enhancement Proposal 428为所谓的 "结构化并发 "引入了一个 API,这个概念旨在改善这种类型需求的代码的实现、可读性和可维护性。

使用 StructuredTaskScope,我们可以把这个例子改写成如下。

    public Invoice createInvoiceSinceJava19(int orderId, int customerId, String language)
throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<Order> orderFuture =
scope.fork(() -> loadOrderFromOrderService(orderId)); Future<Customer> customerFuture =
scope.fork(() -> loadCustomerFromDatabase(customerId)); Future<String> invoiceTemplateFuture =
scope.fork(() -> loadInvoiceTemplateFromFile(language)); scope.join();
scope.throwIfFailed(); Order order = orderFuture.resultNow();
Customer customer = customerFuture.resultNow();
String invoiceTemplate = invoiceTemplateFuture.resultNow(); return new Invoice(order, customer, invoiceTemplate);
}
}

使用 StructuredTaskScope,我们可以将 executor.submit() 替换为 scope.fork()

使用 scope.join(),我们等待所有任务完成--或者至少有一个任务失败或被取消。在后两种情况下,随后的 throwIfFailed() 会抛出一个 ExecutionException 或一个 CancellationException

与旧方法相比,新方法带来了以下改进。

  1. 任务和子任务在代码中形成一个独立的单元,每个子任务都在一个新的虚拟线程中执行。

  2. 一旦其中一个子任务发生错误,所有其他子任务都会被取消。

  3. 当调用线程被取消时,子任务也会被取消。

完整代码如下:

package git.snippets.jdk19;

import jdk.incubator.concurrent.StructuredTaskScope;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future; /**
* 预览功能
* 控制台运行
* 1. 配置Java运行环境是JDK 19
* 2. 注释掉 package 路径
* 3. 在本代码的目录下执行
* 编译:javac --enable-preview -source 19 --add-modules jdk.incubator.concurrent StructuredConcurrencyTest.java
*运行:java --enable-preview --add-modules jdk.incubator.concurrent StructuredConcurrencyTest
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/22
* @since 19
*/
public class StructuredConcurrencyTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
new StructuredConcurrencyTest().createInvoiceSinceJava19(1, 2, "ZH");
} private final ExecutorService executor = Executors.newCachedThreadPool(); // jdk 19 之前
public Invoice createInvoice(int orderId, int customerId, String language) throws ExecutionException, InterruptedException {
Future<Order> orderFuture = executor.submit(() -> loadOrderFromOrderService(orderId)); Future<Customer> customerFuture = executor.submit(() -> loadCustomerFromDatabase(customerId)); Future<String> invoiceTemplateFuture = executor.submit(() -> loadInvoiceTemplateFromFile(language)); Order order = orderFuture.get();
Customer customer = customerFuture.get();
String invoiceTemplate = invoiceTemplateFuture.get(); return Invoice.generate(order, customer, invoiceTemplate);
} // jdk 19 之后
public Invoice createInvoiceSinceJava19(int orderId, int customerId, String language)
throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<Order> orderFuture =
scope.fork(() -> loadOrderFromOrderService(orderId)); Future<Customer> customerFuture =
scope.fork(() -> loadCustomerFromDatabase(customerId)); Future<String> invoiceTemplateFuture =
scope.fork(() -> loadInvoiceTemplateFromFile(language)); scope.join();
scope.throwIfFailed(); Order order = orderFuture.resultNow();
Customer customer = customerFuture.resultNow();
String invoiceTemplate = invoiceTemplateFuture.resultNow(); return new Invoice(order, customer, invoiceTemplate);
}
} private String loadInvoiceTemplateFromFile(String language) {
return language;
} private Customer loadCustomerFromDatabase(int customerId) {
return new Customer(customerId);
} private Order loadOrderFromOrderService(int orderId) {
return new Order(orderId);
}
} class Invoice {
// TODO
public Invoice(Order order, Customer customer, String invoiceTemplate) { } public static Invoice generate(Order order, Customer customer, String invoiceTemplate) {
return null;
}
} class Order {
private int id; public Order(int orderId) {
this.id = orderId;
}
} class Customer {
private int id; public Customer(int customerId) {
this.id = customerId;
}
}

Vector API(第四次预览)

新的 Vector API与java.util.Vector类没有关系。事实上,它是关于数学向量计算的新 API 及其与现代SIMD(单指令-多数据)CPU的映射。

详见:JDK Enhancement Proposal 426

弃用和删除的一些 API

在 Java SE 19 中,一些函数被标记为 "废弃 "或无法使用。

废弃的 Locale 类构造函数

在 Java SE 19 中,Locale 类的公共构造函数被标记为 "弃用"。

相反,我们应该使用新的静态工厂方法Locale.of()。这可以确保每个 Locale 配置只有一个实例。

下面的例子显示了与构造函数相比工厂方法的使用情况。

示例代码如下

package git.snippets.jdk19;

import java.util.Locale;

/**
* @author <a href="mailto:410486047@qq.com">Grey</a>
* @date 2022/9/22
* @since 19
*/
public class LocaleTest {
public static void main(String[] args) {
Locale german1 = new Locale("de"); // deprecated
Locale germany1 = new Locale("de", "DE"); // deprecated Locale german2 = Locale.of("de");
Locale germany2 = Locale.of("de", "DE"); System.out.println("german1 == Locale.GERMAN = " + (german1 == Locale.GERMAN));
System.out.println("germany1 == Locale.GERMANY = " + (germany1 == Locale.GERMANY));
System.out.println("german2 == Locale.GERMAN = " + (german2 == Locale.GERMAN));
System.out.println("germany2 == Locale.GERMANY = " + (germany2 == Locale.GERMANY));
}
}

java.lang.ThreadGroup

在 Java SE 14 和 Java SE 16 中,有几个 Thread 和 ThreadGroup 方法被标记为 "被废弃"

以下这些方法在 Java 19 中已被停用。

ThreadGroup.destroy(); //- 该方法的调用将被忽略。
ThreadGroup.isDestroyed() ;//- 总是返回false。
ThreadGroup.setDaemon() ; //- 设置守护者标志,但这已经没有效果了。
ThreadGroup.suspend();//会抛出一个UnsupportedOperationException。
ThreadGroup.resume();//会抛出一个UnsupportedOperationException。
ThreadGroup.stop();//会抛出一个UnsupportedOperationException。

所有关于 Java SE 19 的新特性见:JDK 19 Release Notes

更多

Java SE 7及以后各版本新增特性

参考资料

Java 19 Features (with Examples)

JDK 19 Release Notes

Java SE 19 新增特性的更多相关文章

  1. Java SE 11 新增特性

    Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  2. Java SE 12 新增特性

    Java SE 12 新增特性 作者:Grey 原文地址:Java SE 12 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  3. Java SE 8 新增特性

    Java SE 8 新增特性 作者:Grey 原文地址: Java SE 8 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...

  4. Java SE 9 新增特性

    Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...

  5. Java SE 10 新增特性

    Java SE 10 新增特性 作者:Grey 原文地址:Java SE 10 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  6. Java SE 13 新增特性

    Java SE 13 新增特性 作者:Grey 原文地址:Java SE 13 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  7. Java SE 14 新增特性

    Java SE 14 新增特性 作者:Grey 原文地址:Java SE 14 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  8. Java SE 15 新增特性

    Java SE 15 新增特性 作者:Grey 原文地址:Java SE 15 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

  9. Java SE 16 新增特性

    Java SE 16 新增特性 作者:Grey 原文地址:Java SE 16 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...

随机推荐

  1. NC17857 起床困难综合症

    NC17857 起床困难综合症 题目 题目描述 21 世纪,许多人得了一种奇怪的病:起床困难综合症,其临床表现为:起床难,起床后精神不佳.作为一名青春阳光好少年,atm 一直坚持与起床困难综合症作斗争 ...

  2. 关于 Python 的 import

    好久以前就被 Python 的相对与绝对导入所困扰.去年粗浅探究后自以为完全理解,近来又因 sys.path[0] 和 os.getcwd() 的不一致而刷新了认知... Python 官方文档 5. ...

  3. ooday08 Java_多态_向下强制转型

    笔记: 多态: 表现: 同一个对象被造型为不同的类型时,有不同的功能 --对象的多态:我.你.水......------所有对象都是多态的(明天体会) 同一类型的引用指向不同的对象时,有不同的实现 - ...

  4. C语言课堂--现代编译环境搭建[2020年7月]

    看过了很多专家吐槽目前的大学c语言教学问题多多: 教材难懂,消磨了学生的兴趣: 环境老旧,都2020了还有在用VC6甚至TurboC 2.0,语法不规范. 轮到自己上课,心想可不能再继续这样的c语言课 ...

  5. 计算机二级Python(第一阶段)

    介绍   本篇文章主要针对于计算机二级考试的崽崽,当然想了解Python和学习Python的崽崽也是可以看本篇文章的:毕竟,手机和电脑都可以运行Python:本篇我文章虽然是笔记,但是也纯靠手打,希望 ...

  6. 20220716-Markdown语法学习

    目录 1.标题部分 2.目录 3.字体部分 4.引用 5.列表 6.代码块 7.表格 8.脚注 9.水平线 效果: 10.引用链接 11.URLs 12.图片 13.emoji 效果: 14.html ...

  7. Vue 状态管理之vuex && {mapState,mapGetters}

    1 # 一.理解vuex 2 1.概念:专门在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读写),也是一种组件间通信的方式,且适用于任意组件间 ...

  8. Charles自动保存响应数据

    本文所有教程及源码.软件仅为技术研究.不涉及计算机信息系统功能的删除.修改.增加.干扰,更不会影响计算机信息系统的正常运行.不得将代码用于非法用途,如侵立删! 操作环境 win10 nexus5x c ...

  9. 《笨办法学Python3 》入坑必备,并不是真笨学!!!

    <笨办法学Python3 >免费下载地址 内容简介 · · · · · · 本书是一本Python入门书籍,适合对计算机了解不多,没有学过编程,但对编程感兴趣的读者学习使用.这本书以习题的 ...

  10. openstack 安装neutron网络服务安装 报错:Unknown operation 'enabled'

     注:这个脚本文件有一个地方是错误的,最后一行需要修改一下 # vim /usr/local/bin/iass-install-neutron-controller-gre.sh # 改systemc ...