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

相关推荐
躺平大鹅4 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者4 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺5 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart6 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP7 小时前
MyBatis-mybatis入门与增删改查
java
孟陬10 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌10 小时前
一站式了解四种限流算法
java·后端·go
华仔啊11 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝12 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java