血赚不亏!Java 17 9 个炸裂特性,程序员看完直呼:太香了!

Java 17 是 2021 年 9 月发布的长期支持(LTS)版本,带来了许多重要的特性和改进,主要包括:

  1. Sealed Classes(密封类) 精确控制类的继承关系
  2. Records(记录类) 简化不可变数据载体的创建
  3. Pattern Matching for instanceof(模式匹配) 简化类型判断和转换代码
  4. Switch Expressions(开关表达式) 支持返回值,更简洁
  5. Text Blocks(文本块) 多行字符串更优雅
  6. ZGC 和 Shenandoah GC 低延迟垃圾回收器正式转正
  7. 其他改进 - var 增强、Stream API 优化、UTF-8 作为默认编码等
  8. RandomGenerator 增强的伪随机数生成器
  9. NullPointerException 增强的空指针异常信息

1. Sealed Classes(密封类)

什么是密封类?

密封类允许精确控制哪些类可以继承它,防止意外的继承和扩展,提高代码的安全性和可维护性。

使用场景

  • 设计一个类层次结构,并且希望只允许特定的子类继承时。

代码结构

代码示例

scala 复制代码
​
/**
 * 功能描述: 密封类 前期指定哪些类可以继承
 *
 * @author Songxianyang
 * @date 2025/11/19 16:32
 */
public sealed class Parent permits Sub1, Sub2 {
}
/**
 * 功能描述:子类必须是 final 或 sealed
 * sealed:子类也可以是密封的,继续限制继承
 *
 * @author Songxianyang
 * @date 2025/11/19 16:33
 */
public final class Sub1 extends Parent {
}
/**
 * 功能描述: 子类也可以是密封的,继续限制继承
 *
 * @author Songxianyang
 * @date 2025/11/19 16:33
 */
public sealed class Sub2 extends Parent permits Sub2_1 {
}
/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2025/11/19 16:37
 */
public final class Sub2_1 extends Sub2 {
}
/**
 * 功能描述: 子类也可以是密封的,继续限制继承
 * 提示:'Sub3' is not allowed in the sealed hierarchy
 * @author Songxianyang
 * @date 2025/11/19 16:33
 */
// public final class Sub3 extends Parent {
// }

运行结果图

2. Records(记录类)

什么是记录类?

record 是一种不可变的数据载体,用于简洁地创建"数据容器"类(如 DTO、VO),自动生成 equals()hashCode()toString() 和访问器方法。

使用场景

  • 需要一个简单的类来存储数据,不需要复杂的业务逻辑时。

代码示例

csharp 复制代码
public record Cat(String name, String id) {
}
/**
 * 功能描述:操作纪录类
 *
 * @author Songxianyang
 * @date 2025/11/19 16:53
 */
public class Main {
    public static void main(String[] args) {
        Cat cat = new Cat("小猫", "1111");
        // 记录类的字段是 final 的,不能修改
        System.out.println(cat.id());
        System.out.println(cat.name());
        System.out.println(cat);
        System.out.println(cat.hashCode());//25070276
        Cat cat1 = new Cat("小猫", "1111");
        System.out.println(cat1.hashCode());//25070276
        // equals==true
    }
}

运行结果图

3. Pattern Matching for instanceof 模式匹配

什么是模式匹配?

简化了 instanceof 的判断和类型转换流程,直接在 instanceof 表达式中声明变量,避免冗余代码。

使用场景

  • 需要判断一个对象的类型,并进行强制转换时。

代码示例

typescript 复制代码
/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2025/11/19 17:13
 */
public class Main {
    public static void main(String[] args) {
        String name = "AAA";
        old(name);
        new0(name);
    }
​
    /**
     * 老式写法
     * @param obj
     */
    private static void old(Object obj) {
        if (obj instanceof String){
           String s= (String)obj;
            System.out.println(s.toLowerCase(Locale.ROOT));
        }
        if (obj instanceof Integer){
            Integer i= (Integer)obj;
            System.out.println(i*2);
        }
    }
​
    /**
     * 新写法
     * 节省代码
     * @param obj
     */
    private static void new0(Object obj) {
        if (obj instanceof String s){
            System.out.println(s.toLowerCase(Locale.ROOT));
        }
        if (obj instanceof Integer i){
            System.out.println(i*2);
        }
    }
}
​

运行结果图

4. Switch Expressions

什么是 Switch 表达式?

switch 语句可以作为表达式使用,直接返回值,并且支持 -> 语法,简化代码结构。

使用场景

  • 需要根据条件返回不同的值时。
  • 根据类型计算结果、映射枚举值等。

代码示例

typescript 复制代码
/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2025/11/19 17:44
 */
public class Main {
    public static void main(String[] args) {
        Integer day = 2;
        System.out.println(getDayOfWeekNew(day));
        System.out.println(getDayOfWeekOld(day));
    }
​
    private static String getDayOfWeekOld(Integer i){
        String res = "";
        switch (i){
            case 1: res="Monday"; break;
            case 2: res="Tuesday"; break;
            default: res="未知"; break;
        }
        return res;
    }
​
    private static String getDayOfWeekNew(Integer i){
        return switch (i){
            case 1 -> "Monday";
            case 2 -> "Tuesday";
            default -> "未知";
        };
    }
}

运行结果图

5. Text Blocks(文本块)

什么是文本块?

用于创建多行字符串,避免手动添加换行符和转义字符,让代码更清晰。

使用场景

  • 需要定义多行字符串时。
  • SQL 查询语句、JSON 数据等。

代码示例

swift 复制代码
/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2025/11/21 11:15
 */
public class Main {
    public static void main(String[] args) {
        String old="SELECT\n" +
                "\t`Host`,`User`,\n" +
                "\tSelect_priv,\n" +
                "\tShow_db_priv,\n" +
                "\tShow_view_priv \n" +
                "FROM\n" +
                "\t`user`;";
​
        String new1= """
                SELECT
                    `Host`,`User`,
                    Select_priv,
                    Show_db_priv,
                    Show_view_priv
                FROM
                    `user`;
                """;
​
        System.out.println(old);
        System.out.println("---------------");
        System.out.println(new1);
    }
}

运行结果图

6. ZGC 和 Shenandoah GC

什么是 ZGC / Shenandoah GC?

  • ZGC:低延迟垃圾回收器,目标是将 GC 停顿时间控制在毫秒级别,适合对响应时间要求高的应用。
  • Shenandoah GC:同样是低延迟 GC,通过并发压缩技术减少停顿时间。

启用方式

在 JVM 启动参数中指定:

ruby 复制代码
# 使用 ZGC
java -XX:+UseZGC -jar your-app.jar
​
# 使用 Shenandoah GC
java -XX:+UseShenandoahGC -jar your-app.jar

7. 其他重要改进

var 关键字增强、toList() 方法

var 可以用于 lambda 表达式的参数类型推断、新增 toList() 方法,更方便地将流转换为列表。

scss 复制代码
/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2025/11/21 11:27
 */
public class Main {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(1, 2, 3);
        System.out.println("Java 17 之前");
        list.forEach((Integer s) -> System.out.println(s));
        System.out.println("Java 17 之后");
        list.forEach((var s)-> System.out.println(s));
        System.out.println("本人常用");
        list.forEach(s-> System.out.println(s));
​
        System.out.println("---------------------");
        // 更方便地将流转换为列表
        List<Integer> collectOld = list.stream().filter(i -> i > 1).collect(Collectors.toList());
        System.out.println(collectOld);
        // 替代 collect(Collectors.toList())
        List<Integer> collectNew = list.stream().filter(i -> i > 1).toList();
        System.out.println(collectNew);
​
    }
}

运行结果图

8.RandomGenerator 增强的伪随机数生成器

使用示例

java 复制代码
/**
 * 标准随机数生成算法名称常量
 */
public final class RandomGeneratorConstants {
​
    private RandomGeneratorConstants() {} // 防止实例化
​
    // JDK 17+ 标准算法
    public static final String L32X64_MIX_RANDOM = "L32X64MixRandom";
    public static final String XOROSHIRO_128_PLUS_PLUS = "Xoroshiro128PlusPlus";
    public static final String XOSHIRO_256_PLUS_PLUS = "Xoshiro256PlusPlus";
    public static final String L64X128_MIX_RANDOM = "L64X128MixRandom";
    public static final String L64X128_STAR_STAR_RANDOM = "L64X128StarStarRandom";
    public static final String L64X256_MIX_RANDOM = "L64X256MixRandom";
    public static final String L128X128_MIX_RANDOM = "L128X128MixRandom";
    public static final String L128X256_MIX_RANDOM = "L128X256MixRandom";
​
    // 传统/安全算法
    public static final String SECURE_RANDOM = "SecureRandom";
    public static final String LEGACY_RANDOM = "Random"; // java.util.Random
    public static final String SPLITTABLE_RANDOM = "SplittableRandom";
​
    // 获取默认算法(JDK 17+ 默认是 L32X64MixRandom)
    public static RandomGenerator getDefault() {
        return RandomGenerator.getDefault();
    }
}
/**
 * 功能描述: 随机数生成
 *
 * @author Songxianyang
 * @date 2025/11/21 15:34
 */
public class Main {
    public static void main(String[] args) {
        RandomGenerator generator = RandomGenerator.of(L64X128_MIX_RANDOM);
        System.out.println("随机生成整数:"+generator.nextInt());
        System.out.println("随机生成小数:"+generator.nextInt());
        System.out.println("随机生成范围内的随机数 0-100");
​
        int nextInt = generator.nextInt(0, 100);
        System.out.println(nextInt);
​
    }
}

运行结果图

9.NullPointerException 增强的空指针异常信息

使用示例:

typescript 复制代码
/**
 * 功能描述:
 *
 * @author Songxianyang
 * @date 2025/11/21 16:46
 */
public class Main {
    static class Person {
        String name;
        Address address;
​
        // getters and setters
        public String getName() { return name; }
        public Address getAddress() { return address; }
    }
​
    static class Address {
        String id;
        String city;
​
        public String getStreet() { return id; }
        public String getCity() { return city; }
    }
​
    /**
     * 以前的异常
     * Exception in thread "main" java.lang.NullPointerException
     *         at Main.main(Main.java:48)
     * 现在的异常:Java17中展示更详细的异常。
     * Exception in thread "main" java.lang.NullPointerException: Cannot invoke "nullpointer.Main$Address.getCity()" because the return value of "nullpointer.Main$Person.getAddress()" is null
     *  at nullpointer.Main.main(Main.java:48)
     * @param args
     */
​
    public static void main(String[] args) {
        Person person = new Person();
        System.out.println(person.getAddress().getCity());
    }
​
    
}

运行结果图

相关推荐
BLOB_1010011 小时前
关于懒人复制idea项目的坑
java·ide·intellij-idea
Moe4881 小时前
Spring Boot 自动配置核心:AutoConfigurationImportSelector 深度解析
java·后端·设计模式
6***x5452 小时前
Java设计模式之策略模式
java·设计模式·策略模式
章鱼哥7302 小时前
Java 策略模式 + 聚合对象:实现多模块的统计与聚合,快速扩展的实战
java·开发语言·策略模式
h***59332 小时前
SpringBoot中如何手动开启事务
java·spring boot·spring
倚肆2 小时前
Java泛型详解:尖括号<>、通配符?与类型参数T
java
韩风6662 小时前
雪花id改多workerID依赖redis
java
BD_Marathon2 小时前
Eclipse 代码自动补全设置
android·java·eclipse
L.EscaRC2 小时前
深入解析SpringBoot中的循环依赖机制与解决方案
java·spring boot·spring·循环依赖