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. NC17059 队列Q

    NC17059 队列Q 题目 题目描述 ZZT 创造了一个队列 Q.这个队列包含了 N 个元素,队列中的第 i 个元素用 \(Q_i\) 表示.Q1 表示队头元素,\(Q_N\) 表示队尾元素.队列中 ...

  2. NC50999 表达式计算4

    NC50999 表达式计算4 题目 题目描述 给出一个表达式,其中运算符仅包含+,-,*,/,^(加 减 乘 整除 乘方)要求求出表达式的最终值 数据可能会出现括号情况,还有可能出现多余括号情况 数据 ...

  3. 异常概念&异常体系和异常分类

    异常概念 异常:指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止. 在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象.Java处 ...

  4. vue封装原生的可预览裁剪上传图片插件H5,PC端都可以使用

    思路:1.先做出一个上传的图片的上传区 <!-- 上传区 --> <label for="fileUp"> <div class="upBo ...

  5. Redis 渐进集群介绍

    redis 凭借着强大的功能和可靠的稳定性,应用场景越来越广.逐渐成为软件开发工程师必备的技能之一. 本篇文章,暂不做基本功能的介绍.直接教大家如何部署redis集群. 集群演进主要分为2部分. 一. ...

  6. 【百度飞桨】手写数字识别模型部署Paddle Inference

    从完成一个简单的『手写数字识别任务』开始,快速了解飞桨框架 API 的使用方法. 模型开发 『手写数字识别』是深度学习里的 Hello World 任务,用于对 0 ~ 9 的十类数字进行分类,即输入 ...

  7. 分支结构_嵌套if的使用

    嵌套if 语法结构: if 条件表达式1: if 内层条件表达式: 内层条件执行体1 else: 内存条件执行体2 else: 条件执行体 外层条件+内层条件的形式 example:#模拟打折的程序如 ...

  8. Linux中安装JDK详细步骤

    一.下载Linux版本的JDK 进入官网下载对应的JDK,下载之前需要先登录 官网地址 -> https://www.oracle.com/ 登录成功后,找到对应的下载位置 根据自己电脑下载对应 ...

  9. 如何给MySQL添加自定义语法 ?

    目录 1 背景 2 新增关键词(token) 3 新增语法 4 类似于PT_partition添加对应的数据结构global_partition_clause 1 背景 MySQL语法解析器用的bis ...

  10. WPF开发随笔收录-WriteableBitmap绘制高性能曲线图

    一.前言 之前分享过一期关于DrawingVisual来绘制高性能曲线的博客,今天再分享一篇通过另一种方式来绘制高性能曲线的方法,也就是通过WriteableBitmap的方式:具体的一些细节这里就不 ...