Java SE 25新增特性

Java SE 25新增特性

作者:Grey

原文地址:

博客园:Java SE 25 新增特性

CSDN:Java SE 25 新增特性

源码

源仓库: Github:java_new_features

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

你可以在一个模式(pattern)之后,通过 when 子句紧跟一个布尔表达式。这种用法被称为"带守卫的模式"(Guarded Pattern)。when 子句中的布尔表达式本身,就叫做"守卫"(Guard)。一个值,只有在同时满足两个条件时,才能成功匹配一个"带守卫的模式":

  • 第一,这个值要符合模式本身的要求;
  • 第二,紧随其后的"守卫"表达式必须计算结果为真。

该特性在 Java SE 23 中首次作为预览功能推出,在 Java SE 24 中再度预览。在当前这个版本中,它将再一次以预览的形式发布,并且没有进行任何重大修改。

示例代码如下:

java 复制代码
package git.snippets.jdk25;
/**
 * When Clause
 * @since 25
 */

public class WhenClausesTest {
    void main() {
        test("h");
        doubleToRating(100d);
        bigNumbers(100000000000l);
        testSwitch(new R(33));
    }
    static void test(Object obj) {
        switch (obj) {
            case String s when s.length() == 1 -> System.out.println("Short: " + s);
            case String s                      -> System.out.println(s);
            default                            -> System.out.println("Not a string");
        }
    }
    String doubleToRating(double rating) {
        return switch(rating) {
            case 0d -> "0 stars";
            case double d when d > 0d && d < 2.5d
                    -> d + " is not good";
            case double d when d >= 2.5f && d < 5d
                    -> d + " is better";
            case 5d -> "5 stars";
            default -> "Invalid rating";
        };
    }

    void bigNumbers(long v) {
        switch (v) {
            case long x when x < 1_000_000L ->
                    System.out.println("Less than a million");
            case long x when x < 1_000_000_000L ->
                    System.out.println("Less than a billion");
            case long x when x < 1_000_000_000_000L ->
                    System.out.println("Less than a trillion");
            case long x when x < 1_000_000_000_000_000L ->
                    System.out.println("Less than a quadrillion");
            default -> System.out.println("At least a quadrillion");
        }
    }
    record R(int x) { }
    // ...
    static void testSwitch(R r) {
        switch(r) {
            case R(int x) when x >= 5 -> System.out.println(x + " => 5");
            default -> System.out.println(r.x + " < 5");
        }
    }
}

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

你可以通过一条声明,就导入一个模块(module)所导出的所有包(package)。参考JEP 511

思考下面这个例子,它导入了四个类:

java 复制代码
// 代码部分保留原文
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

// ...

在这个例子中,你可以用"按需类型导入声明"(type-import-on-demand declarations,也就是我们常说的通配符 * 导入)来替换那四条"单类型导入声明"。但即便如此,你仍然需要三条声明:

java 复制代码
import java.util.*;
import java.util.function.*;
import java.util.stream.*;

然而,由于 java.base 这个模块本身就导出了 java.utiljava.util.functionjava.util.stream 这几个包,所以,你现在可以把上面那三条声明,用一条模块导入声明来代替:

java 复制代码
import module java.base;

一条模块导入声明遵循以下格式:

java 复制代码
import module M;

它会按需导入以下所有公共的顶级类和接口:

  • 模块 M 直接导出给当前模块的那些包。

  • 因读取模块 M,而导致当前模块需要间接读取的其他模块所导出的包。这个机制使得一个程序可以直接使用某个模块的 API,而无需手动导入该 API 可能引用到的、来自其他模块的所有类和接口。

举个例子,import module java.sql; 这条声明,其效果等同于 import java.sql.*;并且还加上了java.sql 模块间接导出包的按需导入,这些间接导出的包就包括了 java.loggingjava.xml

示例代码:

java 复制代码
package git.snippets.jdk25;

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

public class ModuleImportDeclarationsTest {
    void main() throws ParserConfigurationException, SAXException {
        System.out.println(groupByFirstLetter("a", "abc", "bcd", "ddd", "dddc", "dfc", "bc"));
// 我们不需要显式导入 SAXParserFactory 和 SAXParser,也不需要显式导入 java.xml 模块:
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
    }

    public static Map<Character, List<String>> groupByFirstLetter(String... values) {
        return Stream.of(values).collect(Collectors.groupingBy(s -> Character.toUpperCase(s.charAt(0))));
    }
}

Compact Source Files and Instance Main Methods

这项功能最初在 Java SE 21 中第一次预览版,并在 Java SE 22、23 和 24 中持续预览。在当前版本中,它已成为一项正式功能,其标题也经过了修订。

该版本的具体更新如下:

  • 用于处理基本控制台输入/输出的新类 IO,其位置已从 java.io 包移动到了 java.lang 包。这意味着java.lang 包里的所有东西都会被虚拟机自动导入,所以现在每个源文件都会默认包含 IO 类,你无需再手动去 import 它了。这让代码更加干净。

  • IO 类中的静态方法(比如 println),将不再被默认导入到那些简化的源文件中。这和预览版的行为不同了。因此,现在调用这些方法时必须明确地写出类名,例如 IO.println("Hello, world!"),而不能再像之前那样直接调用 println。当然,如果你觉得每次都写 IO. 很麻烦,也可以通过显式的静态导入(static import)来恢复之前的便捷性。

  • IO 类的底层实现也变了。它现在是基于我们非常熟悉的 System.outSystem.in,而不再是 java.io.Console 类。这是一个内部实现细节的改变,但它意味着 IO 类的行为会和标准的系统输入输出流更加一致。

    示例代码如下:

java 复制代码
/**
 * @author <a href="mailto:410486047@qq.com">Grey</a>
 * @date 2025/09/17
 * @since 25
 */
void main() {
    IO.println("hello world");
}

更多

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

参考资料

Java Language Changes for Java SE 24

JDK 24 Release Notes

JAVA 25 FEATURES(WITH EXAMPLES

相关推荐
xqqxqxxq5 小时前
Java AI智能P图工具技术笔记
java·人工智能·笔记
谷雨不太卷5 小时前
进程的状态码
java·前端·算法
顾温5 小时前
default——C#/C++
java·c++·c#
空中海5 小时前
02 ArkTS 语言与工程规范
java·前端·spring
楚国的小隐士5 小时前
在AI时代,如何从0接手一个项目?
java·ai·大模型·编程·ai编程·自闭症·自闭症谱系障碍·神经多样性
yaki_ya5 小时前
yaki-C语言:从概念基础到内存解析---数组(array)完全指南
java·c语言·算法
刃神太酷啦5 小时前
扒透 STL 底层!map/set 如何封装红黑树?迭代器逻辑 + 键值限制全手撕----《Hello C++ Wrold!》(23)--(C/C++)
java·c语言·javascript·数据结构·c++·算法·leetcode
亚历克斯神5 小时前
Java 25 模式匹配增强:让代码更简洁优雅
java·spring·微服务
星辰徐哥5 小时前
Rust异步测试与调试的实践指南
android·java·rust
星河耀银海5 小时前
C++ 运算符重载:自定义类型的运算扩展
android·java·c++