Java 17+ 新特性详解:Record 与 Pattern Matching

一、概述

Java 17 是继 Java 11 之后的第二个长期支持(LTS)版本,标志着 Java 语言现代化进程的重要里程碑。从 Java 17 开始,Java 语言引入了多项旨在提高开发效率、增强代码可读性和安全性的新特性。其中,RecordPattern Matching 是两个最具革命性的特性,它们从根本上改变了 Java 的数据建模和条件处理方式。

1.1 Java 版本演进路线

  • Java 14-16:Record 和 Pattern Matching 作为预览特性引入
  • Java 17:正式成为 LTS 版本,包含多项稳定特性
  • Java 21:最新 LTS 版本,Pattern Matching for switch 正式发布

二、Record(记录类)

2.1 什么是 Record?

Record 是一种特殊的类,用于声明不可变的数据载体。它自动生成构造函数、访问器、equals()hashCode()toString() 方法,极大地简化了数据类的编写。

2.2 基本语法

// 传统 Java Bean 写法
public class Person {
    private final String name;
    private final int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    // 省略 getter、equals、hashCode、toString 方法(通常需要50+行代码)
}

// 使用 Record 简化写法
public record Person(String name, int age) { }

2.3 核心特性

2.3.1 自动生成的方法
public record Point(int x, int y) { }

// 自动生成以下方法:
// 1. 规范构造函数:Point(int x, int y)
// 2. 访问器方法:x() 和 y()(注意:不是 getX() 和 getY())
// 3. equals() 和 hashCode()
// 4. toString():格式为 "Point[x=10, y=20]"
2.3.2 自定义构造函数
public record Person(String name, int age) {
    // 紧凑构造函数(Compact Constructor)
    public Person {
        if (age < 0) {
            throw new IllegalArgumentException("年龄不能为负数");
        }
        // 不需要显式赋值,编译器会自动处理
    }
    
    // 自定义构造函数
    public Person(String name) {
        this(name, 0); // 必须调用主构造函数
    }
}
2.3.3 静态成员和实例方法
public record Circle(double radius) {
    // 静态字段
    private static final double PI = 3.14159;
    
    // 静态方法
    public static Circle unitCircle() {
        return new Circle(1.0);
    }
    
    // 实例方法
    public double area() {
        return PI * radius * radius;
    }
    
    // 可以重写自动生成的方法
    @Override
    public String toString() {
        return String.format("Circle[radius=%.2f]", radius);
    }
}

2.4 Record 的限制

  1. 不可变性:所有字段都是 final
  2. 不能继承:Record 隐式继承 java.lang.Record,不能继承其他类
  3. 不能声明实例字段:只能有记录组件(record components)
  4. 不能是抽象的:Record 总是 final

2.5 使用场景

// 1. DTO(数据传输对象)
public record UserDTO(Long id, String username, String email) { }

// 2. 值对象
public record Money(BigDecimal amount, Currency currency) { }

// 3. 复合键
public record OrderKey(String customerId, LocalDate orderDate, int sequence) { }

// 4. 方法返回多个值
public record Pair<T, U>(T first, U second) { }

public Pair<Integer, String> findMinMax(int[] array) {
    // 计算逻辑
    return new Pair<>(min, max);
}

三、Pattern Matching(模式匹配)

3.1 演进历程

Pattern Matching 在 Java 中分阶段引入:

  • Java 16:Pattern Matching for instanceof
  • Java 17:Pattern Matching for switch(预览)
  • Java 21:Pattern Matching for switch(正式发布)

3.2 Pattern Matching for instanceof

3.2.1 传统写法的问题
// 传统写法:冗长且容易出错
if (obj instanceof String) {
    String str = (String) obj; // 需要显式转型
    System.out.println(str.length());
}
3.2.2 新模式写法
// 新模式:简洁安全
if (obj instanceof String str) {
    // str 自动转型并绑定
    System.out.println(str.length());
}

// 结合条件判断
if (obj instanceof String str && str.length() > 5) {
    System.out.println("长字符串: " + str);
}

3.3 Pattern Matching for switch

3.3.1 基本语法
// Java 21 正式语法
Object obj = "Hello";

String result = switch (obj) {
    case Integer i -> String.format("整数: %d", i);
    case String s -> String.format("字符串: %s", s);
    case null -> "空值";
    default -> "未知类型";
};
3.3.2 类型模式(Type Patterns)
static String formatter(Object obj) {
    return switch (obj) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> obj.toString();
    };
}
3.3.3 守卫模式(Guarded Patterns)
static void test(Object obj) {
    switch (obj) {
        case String s when s.length() > 5 -> 
            System.out.println("长字符串: " + s);
        case String s -> 
            System.out.println("短字符串: " + s);
        case Integer i when i > 0 -> 
            System.out.println("正整数: " + i);
        default -> 
            System.out.println("其他类型");
    }
}
3.3.4 空值处理
// 传统 switch 不能处理 null
// 新模式可以显式处理 null
String result = switch (str) {
    case null -> "空值";
    case "A", "B", "C" -> "字母";
    case String s when s.length() == 1 -> "单个字符";
    default -> "其他";
};
3.3.5 嵌套模式(Nested Patterns)
record Point(int x, int y) { }

static void process(Object obj) {
    switch (obj) {
        case Point(int x, int y) when x == y -> 
            System.out.println("点在直线上: (" + x + ", " + y + ")");
        case Point(int x, int y) -> 
            System.out.println("点坐标: (" + x + ", " + y + ")");
        default -> 
            System.out.println("未知对象");
    }
}

3.4 Record 模式(Record Patterns) - Java 19 预览

3.4.1 解构 Record
record Point(int x, int y) { }
record Line(Point start, Point end) { }

// 嵌套解构
static void printLine(Line line) {
    if (line instanceof Line(Point(var x1, var y1), Point(var x2, var y2))) {
        System.out.printf("线段从 (%d,%d) 到 (%d,%d)%n", x1, y1, x2, y2);
    }
}

// 在 switch 中使用
static String describe(Object obj) {
    return switch (obj) {
        case Point(int x, int y) when x == 0 && y == 0 -> "原点";
        case Point(int x, int y) when x == y -> "在直线 y=x 上";
        case Point(int x, int y) -> "点 (" + x + ", " + y + ")";
        default -> "其他";
    };
}

四、Record 与 Pattern Matching 的结合使用

4.1 数据处理的完美组合

// 定义数据模型
sealed interface Shape permits Circle, Rectangle, Triangle { }
record Circle(double radius) implements Shape { }
record Rectangle(double width, double height) implements Shape { }
record Triangle(double base, double height) implements Shape { }

// 使用模式匹配处理不同形状
static double area(Shape shape) {
    return switch (shape) {
        case Circle(double r) -> Math.PI * r * r;
        case Rectangle(double w, double h) -> w * h;
        case Triangle(double b, double h) -> 0.5 * b * h;
    };
}

// 复杂模式匹配
static String analyze(Shape shape) {
    return switch (shape) {
        case Circle(var r) when r > 10 -> "大圆";
        case Circle(var r) when r > 5 -> "中圆";
        case Circle(var r) -> "小圆";
        case Rectangle(var w, var h) when w == h -> "正方形";
        case Rectangle(var w, var h) -> "长方形";
        case Triangle t -> "三角形";
    };
}

4.2 实际应用示例:JSON 解析

// 定义 JSON 节点类型
sealed interface JsonValue permits JsonObject, JsonArray, JsonString, JsonNumber, JsonBoolean, JsonNull { }
record JsonObject(Map<String, JsonValue> properties) implements JsonValue { }
record JsonArray(List<JsonValue> elements) implements JsonValue { }
record JsonString(String value) implements JsonValue { }
record JsonNumber(double value) implements JsonValue { }
record JsonBoolean(boolean value) implements JsonValue { }
record JsonNull() implements JsonValue { }

// 使用模式匹配遍历 JSON
static void traverse(JsonValue json) {
    switch (json) {
        case JsonObject(var props) -> 
            props.forEach((key, value) -> {
                System.out.println("键: " + key);
                traverse(value);
            });
        case JsonArray(var elements) -> 
            elements.forEach(JsonTraverser::traverse);
        case JsonString(var s) -> 
            System.out.println("字符串: " + s);
        case JsonNumber(var n) -> 
            System.out.println("数字: " + n);
        case JsonBoolean(var b) -> 
            System.out.println("布尔值: " + b);
        case JsonNull() -> 
            System.out.println("空值");
    }
}

五、其他 Java 17+ 重要特性

5.1 密封类(Sealed Classes) - Java 17 正式

// 定义密封接口
public sealed interface Shape permits Circle, Rectangle, Triangle {
    double area();
}

// 子类必须是 final、sealed 或 non-sealed
public final class Circle implements Shape { /* ... */ }
public non-sealed class Rectangle implements Shape { /* ... */ }
public sealed class Triangle permits EquilateralTriangle, RightTriangle { /* ... */ }

5.2 文本块(Text Blocks) - Java 15 正式

// 传统字符串
String html = "<html>\n" +
              "    <body>\n" +
              "        <p>Hello, world</p>\n" +
              "    </body>\n" +
              "</html>\n";

// 文本块
String html = """
    <html>
        <body>
            <p>Hello, world</p>
        </body>
    </html>
    """;

5.3 增强的伪随机数生成器

// 新的 RandomGenerator 接口
RandomGenerator generator = RandomGenerator.getDefault();
RandomGenerator.StreamableGenerator streamable = RandomGenerator.of("L64X128MixRandom");

// 生成流
IntStream randomInts = generator.ints(10, 0, 100);

六、最佳实践与注意事项

6.1 Record 使用建议

  1. 适合场景:纯数据载体、值对象、DTO、不可变配置
  2. 不适合场景:需要继承、需要可变状态、复杂业务逻辑的类
  3. 命名规范:使用名词或名词短语,如 PointUserInfo
  4. 验证逻辑:在紧凑构造函数中添加参数验证

6.2 Pattern Matching 使用建议

  1. 替代 instanceof 链:优先使用模式匹配替代传统的 instanceof 检查
  2. 利用守卫条件:使用 when 子句处理复杂条件
  3. 处理 null:显式处理 null 情况,避免 NPE
  4. 结合密封类:模式匹配与密封类结合可实现完备性检查

6.3 性能考虑

  1. Record:编译时生成代码,运行时无额外开销
  2. Pattern Matching:编译器优化,性能与传统写法相当
  3. Switch 表达式:使用箭头语法(->)避免穿透(fall-through)

七、迁移策略

7.1 从传统 Java Bean 迁移到 Record

// 迁移前
public class Person {
    private final String name;
    private final int age;
    
    // 构造函数、getter、equals、hashCode、toString(50+行)
}

// 迁移后
public record Person(String name, int age) {
    // 可选的验证逻辑
    public Person {
        if (age < 0) throw new IllegalArgumentException();
    }
}

7.2 重构条件逻辑

// 重构前
if (obj instanceof String) {
    String str = (String) obj;
    if (str.length() > 10) {
        // 处理长字符串
    }
} else if (obj instanceof Integer) {
    Integer num = (Integer) obj;
    // 处理整数
}

// 重构后
switch (obj) {
    case String s when s.length() > 10 -> processLongString(s);
    case String s -> processString(s);
    case Integer i -> processInteger(i);
    default -> handleOther(obj);
}

八、总结

Java 17+ 的 Record 和 Pattern Matching 特性标志着 Java 语言向现代化、声明式编程风格的重要转变:

8.1 Record 的核心价值

  • 简洁性:大幅减少样板代码
  • 不可变性:自动生成不可变类,提高线程安全性
  • 值语义:自动实现 equals()hashCode(),适合作为 Map 的键
  • 可读性:明确声明数据模型,代码意图清晰

8.2 Pattern Matching 的核心价值

  • 安全性:消除显式转型,减少 ClassCastException
  • 表达力:将类型检查、转型和变量绑定合并为一步操作
  • 完备性:与密封类结合,编译器可检查模式匹配的完备性
  • 可维护性:简化复杂条件逻辑,提高代码可读性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

n8n

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值