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. RASP | 远程Java应用的RASP调试教程

    远程Java应用的RASP调试教程 介绍 Java RASP是基于Java Agent技术实现的,而Java Agent代码无法独立启动,必须依赖于一个Java运行时程序才能运行. 如何调试一个Jav ...

  2. WPS前骨干历时10年打造新型软件,Excel用户:我为此改用WPS

    办公软件本质是降本增效,我们常见的金山WPS软件.微软office Excel.仓库管理WMS.生产管理MES等都是如此,但是有一款软件却让人变得更"懒惰",而且还是针对于有进取心 ...

  3. 数码管动态显示Verilog实现(参考小梅哥教程)(视觉暂留)

    一个数码管有九个引脚,控制八段二极管的亮灭,用以显示需要的数字. 当有N个数码管时,一个一个控制的话需要N x 9 个引脚,消耗资源较多. 因此可以利用动态显示的方案通过人眼的视觉暂留特性达到静态显示 ...

  4. SSH远程登录:两台或多台服务器之间免密登录设置

    有两台(或多台)同局域网的服务器A:192.168.2.21,B:192.168.2.25.让A,B这两台服务器之间能两两互相免密登录,并且每台服务器都可以自我免密登录(自我免密登录即:ssh loc ...

  5. 15分钟搭建RocketMQ源码调试环境

    下载源码 下载源码,github页面选择(rocketmq-all-4.7.1)版本压缩包,https://github.com/apache/rocketmq/tags 导入IDEA 1. 使用ID ...

  6. CC2530_ZigBee+华为云IOT:设计一套属于自己的冷链采集系统

    摘要:以CC2530单片机为核心器件,设计一个冷链环境信息采集系统,利用传感器技术对冷藏仓内的环境参数进行采集,上传到华为云物联网云平台,然后通过手机端或移动端进行显示,便于分析,观察冷链环境信息. ...

  7. Windows Embedded CE 6.0开发环境的搭建(2)

    最近开始在学习嵌入式,在这里首先得安装Windows Embedded CE 6.0,其中遇到了很多问题,电脑的系统以及相关配置都会在安装过程中受到影响,因此笔者就安装中的问题以及环境搭建来介绍一下. ...

  8. Linux 的常用基本命令

    一.Linux 的常用基本命令..................................................................................... ...

  9. Luogu2073 送花 (平衡树)

    打感叹号处为傻逼处 #include <iostream> #include <cstdio> #include <cstring> #include <al ...

  10. java学习第一天.day04

    顺序结构 代码里没有流程控制,程序是按照书写的格式从上而下一行一行执行的, 一条语句执行完之后继续执行下一条语句,中间没有判断和跳转,直到程序的结束. 选择结构 选择结构也被称为分支结构.代码根据逻辑 ...