Java SE 24 新增特性

作者:Grey

原文地址:

博客园:Java SE 24 新增特性

CSDN:Java SE 24 新增特性

源码

源仓库: Github:java_new_features

Patterns、instanceof 和 switch 可以匹配更多类型(第二次预览)

通过允许在所有模式上下文中使用原始类型来增强模式匹配,Java 16 中引入了与 instanceof 的模式匹配,在 Java 21 中引入了与 switch 的模式匹配。

public class PrimitiveTypesTest {
void main() {
test1("hello world");
test2("hello world");
test1(56);
test2(56);
test1(java.time.LocalDate.now());
test2(java.time.LocalDate.now());
} private static void test1(Object obj) {
if (obj instanceof String s && s.length() >= 5) {
System.out.println(s.toUpperCase());
} else if (obj instanceof Integer i) {
System.out.println(i * i);
} else {
System.out.println(obj);
}
} private static void test2(Object obj) {
switch (obj) {
case String s when s.length() >= 5 -> System.out.println(s.toUpperCase());
case Integer i -> System.out.println(i * i);
case null, default -> System.out.println(obj);
}
}
}

JEP 455 在 Java 23 中引入了两项变更:

  • 可以在 switch 表达式和语句中使用所有基元类型,包括 long、float、double 和 boolean。

  • 其次,我们还可以在模式匹配中使用所有基元类型,包括 instanceof 和 switch。

在这两种情况下,即通过 long、float、double 和布尔类型进行 switch 以及使用基元变量进行模式匹配时,与所有新的 switch 功能一样,switch 必须要涵盖所有可能的情况。

private static void test3(int x) {
switch (x) {
case 1, 2, 3 -> System.out.println("Low");
case 4, 5, 6 -> System.out.println("Medium");
case 7, 8, 9 -> System.out.println("High");
}
}

模块导入声明(第二次预览)

这个功能在JDK 23 上是第一次预览,主要功能是通过简洁地导入模块导出的所有包的功能来增简化了模块库的重复使用,但不要求导入代码本身必须在模块中。

自 Java 1.0 起,java.lang 包中的所有类都会自动导入到每个 .java 文件中。这就是为什么我们无需导入语句就能使用 ObjectStringIntegerExceptionThread 等类的原因。

我们还可以导入完整的包。例如,导入 java.util.* 意味着我们不必单独导入 ListSetMapArrayListHashSetHashMap 等类。

JEP 467现在允许我们导入完整的模块,更准确地说,是导入模块导出的包中的所有类。

例如,我们可以按如下方式导入完整的 java.base 模块,然后使用该模块中的类(例如 ListMapCollectorsStream),而无需进一步导入:

package git.snippets.jdk23;

import module java.base;

public class ModuleImportDeclarationsTest {
void main() {
System.out.println(groupByFirstLetter("a", "abc", "bcd", "ddd", "dddc", "dfc", "bc"));
} public static Map<Character, List<String>> groupByFirstLetter(String... values) {
return Stream.of(values).collect(Collectors.groupingBy(s -> Character.toUpperCase(s.charAt(0))));
}
}

如果有两个同名的导入类,例如下面示例中的 Date,编译器就会出错:

import module java.base;
import module java.sql;

如果一个导入模块临时导入了另一个模块,那么我们也可以使用临时导入模块导出包中的所有类,而无需显式导入。

例如,java.sql 模块转义导入了 java.xml 模块:

module java.sql {
. . .
requires transitive java.xml;
. . .
}

因此,在下面的示例中,我们不需要显式导入 SAXParserFactory 和 SAXParser,也不需要显式导入 java.xml 模块:

SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();

灵活的构造函数主体(第三次预览)

这个功能在 JDK 23 上是第二次预览,现在是第三次预览,下述代码中,Child1的构造函数,只能先通过super构造父类,然后才能初始化子类的 b 这个变量。

public class FlexibleConstructorBodies {
void main() {
new Child1(1, 2);
}
} class Parent {
private final int a; public Parent(int a) {
this.a = a;
printMe();
} void printMe() {
System.out.println("a = " + a);
}
} // JDK 23 之前
class Child1 extends Parent {
private final int b; public Child1(int a, int b) {
super(verifyParamsAndReturnA(a, b));
this.b = b;
} @Override
void printMe() {
super.printMe();
System.out.println("b = " + b);
} private static int verifyParamsAndReturnA(int a, int b) {
if (a < 0 || b < 0) throw new IllegalArgumentException();
return a;
}
}

当我们执行

new Child1(1,2);

这段代码的时候,本来我们期待返回的是

a = 1
b = 2

但是由于父类在构造时候调用了printMe(),且这个调用是在 b 变量初始化之前调用的,所以导致程序执行的结果是

a = 1
b = 0

今后,在使用 super(...) 调用父类构造函数之前,以及在使用 this(...) 调用本类的构造函数之前,我们可以执行任何不访问当前构造实例(即不访问其字段)的代码,

此外,我们还可以初始化正在构造的实例的字段。详见JEP 482

在 JDK 24 上,上述代码可以调整为:

class Child2 extends Parent {
private final int b; public Child2(int a, int b) {
if (a < 0 || b < 0) throw new IllegalArgumentException();
this.b = b;
super(a);
} @Override
void printMe() {
super.printMe();
System.out.println("b = " + b);
}
}

其中构造函数中,a和b的初始化和判断,都可以在super(...)函数调用之前,

执行

new Child2(1,2);

打印结果为预期结果

a = 1
b = 2

main方法的精简写法(第四次预览)

最早出现在 JDK 21 中,见Java SE 21 新增特性

原来我们写一个main方法,需要

public class UnnamedClassesAndInstanceMainMethodsTest {

    public static void main(String[] args) {
System.out.println("Hello World!");
} }

而且Java文件的名称需要和UnnamedClassesAndInstanceMainMethodsTest保持一致,到了JDK 24,上述代码可以简化成

void main() {
System.out.println("hello world");
}

甚至连 public class ... 这段也不需要写,在JDK 24版本中,这个功能是第四次预览。

结构化并发(第四次预览)

JEP 499 引入了结构化并发(Structured Concurrency),它确保相关的任务一起启动、一起管理,使并发编程更安全、更易于理解

让我们通过一个简单的示例来理解它:并行获取用户数据和订单数据,并比较传统方式结构化并发的实现方式。

传统方式(没有结构化并发)

在传统方法中,我们使用 ExecutorService 并手动管理任务执行和取消:

import java.util.concurrent.*;

public class TraditionalConcurrencyExample {
private static final ExecutorService executor = Executors.newFixedThreadPool(2); public static void main(String[] args) throws ExecutionException, InterruptedException {
Future<String> userFuture = executor.submit(() -> fetchUserData());
Future<String> orderFuture = executor.submit(() -> fetchOrderData()); try {
String userData = userFuture.get(); // 阻塞直到用户数据返回
String orderData = orderFuture.get(); // 阻塞直到订单数据返回
System.out.println("用户: " + userData + ", 订单: " + orderData);
} finally {
executor.shutdown();
}
} static String fetchUserData() {
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
return "用户数据";
} static String fetchOrderData() {
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
return "订单数据";
}
}

存在的问题:

子任务管理复杂——没有清晰的父子关系,难以控制任务的生命周期。

手动异常处理——需要自行管理任务失败时的行为。

资源泄漏风险——如果一个任务失败,另一个任务可能仍在运行,可能导致不一致的状态。

使用结构化并发

现在,我们使用 StructuredTaskScope 让任务在相同的作用域中执行,并确保它们要么一起完成,要么一起失败

import java.util.concurrent.*;
import jdk.incubator.concurrent.StructuredTaskScope; public class StructuredConcurrencyExample {
public static void main(String[] args) throws InterruptedException, ExecutionException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
StructuredTaskScope.Subtask<String> userTask = scope.fork(() -> fetchUserData());
StructuredTaskScope.Subtask<String> orderTask = scope.fork(() -> fetchOrderData()); scope.join(); // 等待所有任务完成
scope.throwIfFailed(); // 如果有任务失败,取消所有任务并抛出异常 String userData = userTask.get();
String orderData = orderTask.get();
System.out.println("用户: " + userData + ", 订单: " + orderData);
}
} static String fetchUserData() {
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
return "用户数据";
} static String fetchOrderData() {
try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
return "订单数据";
}
}

结构化并发的优势如下:

任务管理更清晰——所有任务都在 StructuredTaskScope 作用域内,代码更加易读

自动清理——如果任何一个任务失败,所有任务都会被取消,不会出现部分完成的情况。

更好的错误处理——异常可以在 scope.throwIfFailed() 统一管理,避免手动 try-catch。

更容易调试——所有任务都有明确的父作用域,方便排查问题。

结构化并发(Structured Concurrency)让并行任务的执行更安全、更易维护。它确保任务要么一起成功完成,要么一起失败取消,避免了传统并发编程中的各种问题,如任务泄漏、异常传播困难等。

更多

Java SE 7及以后各版本新增特性,持续更新中...

参考资料

Java Language Changes for Java SE 24

JDK 24 Release Notes

JAVA 24 FEATURES(WITH EXAMPLES

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

  1. Java SE 8 新增特性

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

  2. Java SE 9 新增特性

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

  3. Java SE 10 新增特性

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

  4. Java SE 11 新增特性

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

  5. Java SE 12 新增特性

    Java SE 12 新增特性 作者:Grey 原文地址:Java SE 12 新增特性 源码 源仓库: 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 ...

  10. Java SE 17 新增特性

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

随机推荐

  1. Qt音视频开发19-海康sdk录像存储

    一.前言 关于调用海康sdk来进行录像存储,整体的框架架构处理流程沿袭了之前vlc内核.ffmpeg内核.mpv内核的做法,定时存储这块,开个定时器判断,到了时间则先关闭原来的录像存储,然后在开始一个 ...

  2. error C2065: “CV_DATA_AS_ROW”: 未声明的标识符

    ce_dect\main_face.cpp(117): error C2065: "CV_DATA_AS_ROW": 未声明的标识符将 "CV_PCA_DATA_AS_R ...

  3. OpenMMLab AI实战营 第六课笔记

    OpenMMLab AI实战营 第六课笔记 目录 OpenMMLab AI实战营 第六课笔记 1.什么是语义分割 1.1 语义分割的应用 1.1.1 应用:无人驾驶汽车 1.1.2 应用:人像分割 1 ...

  4. 【转】Mysql索引失效的情况

    在工作中经常能遇到索引失效的情况,只要索引失效就导致了SQL查询慢,服务响应慢,用户体验差的情况:所以下面我们就讨论一下MySQL中索引失效的情况 口诀 全职匹配我最爱,最左前缀要遵守: 带头大哥不能 ...

  5. 并发编程之 ConcurrentLinkedQueue 源码

    文章目录1 ConcurrentLinkedQueue的概述2 ConcurrentLinkedQueue的实现2.1 基本结构2.2 构造器2.2.1 ConcurrentLinkedQueue2. ...

  6. smart_web 管理端基本说明

    smart_web 操作手册 1. smart_web 是什么? smart_web 是 smart_rtmpd 的付费版本,拥有比免费版本更多的功能支持,基于 web 的管理方式,让您随时随地在大部 ...

  7. 加速 AI 训推:Lepton AI 如何构建多租户、低延迟云存储平台

    Lepton AI 是一款面向开发者的 AI 平台,旨在提供易用.高效且可扩展的基础设施能力.该平台适用于各种训练.推理需求,GPU充足,在保证高性能的同时,能够灵活应对不断变化的工作负载.用户可以快 ...

  8. Paillier算法

    介绍 1999年欧密会上,首次提出Paillier算法,2001年,Damgard等人对该方案简化,推出当前最优的Paillier方案. 加密方案 Carmichael函数 困难问题 合数剩余类问题( ...

  9. [python]png转webp的命令行工具

    前言 网页上使用webp格式的图片更加省网络流量和存储空间,但本地图片一般是png格式的,所以考虑用python的pillow库将png格式的图片转换为webp格式. 需求: 可以在系统任意地方调用. ...

  10. 解决Git拉取出现“bad config line 1 in file C:\Users\quber/.gitconfig”的错误

    1.问题描述 我们在拉取Git项目的时候,突然出现如下图所示的错误提示: 2.解决办法 定位到.gitconfig文件,然后将其删除掉: 然后在项目文件夹中点击鼠标右键,选择Git Bash Here ...