Java SE 19 新增特性
Java SE 19 新增特性
作者:Grey
原文地址:
源码
镜像仓库: 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
。
与旧方法相比,新方法带来了以下改进。
任务和子任务在代码中形成一个独立的单元,每个子任务都在一个新的虚拟线程中执行。
一旦其中一个子任务发生错误,所有其他子任务都会被取消。
当调用线程被取消时,子任务也会被取消。
完整代码如下:
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 19 Features (with Examples)
Java SE 19 新增特性的更多相关文章
- Java SE 11 新增特性
Java SE 11 新增特性 作者:Grey 原文地址:Java SE 11 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 12 新增特性
Java SE 12 新增特性 作者:Grey 原文地址:Java SE 12 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 8 新增特性
Java SE 8 新增特性 作者:Grey 原文地址: Java SE 8 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...
- Java SE 9 新增特性
Java SE 9 新增特性 作者:Grey 原文地址: Java SE 9 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new_ ...
- Java SE 10 新增特性
Java SE 10 新增特性 作者:Grey 原文地址:Java SE 10 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 13 新增特性
Java SE 13 新增特性 作者:Grey 原文地址:Java SE 13 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 14 新增特性
Java SE 14 新增特性 作者:Grey 原文地址:Java SE 14 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 15 新增特性
Java SE 15 新增特性 作者:Grey 原文地址:Java SE 15 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
- Java SE 16 新增特性
Java SE 16 新增特性 作者:Grey 原文地址:Java SE 16 新增特性 源码 源仓库: Github:java_new_features 镜像仓库: GitCode:java_new ...
随机推荐
- NC14380 位数差
NC14380 位数差 题目 题目描述 给一个数组 \({a}\) ,定义 \(h(a,b)\) 为在十进制下 \(a + b\) 与 \(a\) 的位数差,求 \(\displaystyle\sum ...
- NC202498 货物种类
NC202498 货物种类 题目 题目描述 某电商平台有 \(n\) 个仓库,编号从 \(1\) 到 \(n\) . 当购进某种货物的时候,商家会把货物分散的放在编号相邻的几个仓库中. 我们暂时不考虑 ...
- Android 12(S) 图像显示系统 - drm_hwcomposer 简析(下)
必读: Android 12(S) 图像显示系统 - 开篇 合成方式 合成类型的定义:/hardware/interfaces/graphics/composer/2.1/IComposerClien ...
- 小米社区APP深度体验
小米社区APP深度体验 版本:3.0.210928 BUG 1,在暗黑模式下,会员一栏中的成就等级小字未作深色模式调整,从而造成文字难于识别. 2,在暗黑模式下,会员页中底部的会员产品首页视觉没有完美 ...
- Java 范例 - 定时任务
前言 JDK 有两种定时任务的实现,一种是单线程循环判断,另一种则是线程池. 定时器 java.util 包下有 Timer 类可用来实现定时任务,下面是一个简单的例子: Date date = ne ...
- C# MVCapi跨域问题
he 'Access-Control-Allow-Origin' header contains multiple values ', *', but only one is allowed. Or ...
- Seata-初体验以及避坑
Seata是什么 这里引用官方解释 Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务.Seata 将为用户提供了 AT.TCC.SAGA 和 XA 事务模式,为用 ...
- 机器学习(公式推导与代码实现)--sklearn机器学习库
一.scikit-learn概述 1.sklearn模型 sklearn全称是scikit-learn,它是一个基于Python的机器学习类库,主要建立在NumPy.Pandas.SciPy和Ma ...
- Visual Studio Code 中文设置教程
本文仅供学习交流使用,如侵立删!demo下载见文末 Pycharm中文设置教程 1.首先打开VisualStudioCode,点击扩展:extensions. 2.搜索chinese. 3.选择需要的 ...
- redis安装与连接
安装(centos7): yum install redis 启动与停止: systemctl start redis. service systemctl stop redis.service 修改 ...