一、概述
Java 17 是继 Java 11 之后的第二个长期支持(LTS)版本,标志着 Java 语言现代化进程的重要里程碑。从 Java 17 开始,Java 语言引入了多项旨在提高开发效率、增强代码可读性和安全性的新特性。其中,Record 和 Pattern 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 的限制
- 不可变性:所有字段都是
final的 - 不能继承:Record 隐式继承
java.lang.Record,不能继承其他类 - 不能声明实例字段:只能有记录组件(record components)
- 不能是抽象的: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 使用建议
- 适合场景:纯数据载体、值对象、DTO、不可变配置
- 不适合场景:需要继承、需要可变状态、复杂业务逻辑的类
- 命名规范:使用名词或名词短语,如
Point、UserInfo - 验证逻辑:在紧凑构造函数中添加参数验证
6.2 Pattern Matching 使用建议
- 替代 instanceof 链:优先使用模式匹配替代传统的 instanceof 检查
- 利用守卫条件:使用
when子句处理复杂条件 - 处理 null:显式处理 null 情况,避免 NPE
- 结合密封类:模式匹配与密封类结合可实现完备性检查
6.3 性能考虑
- Record:编译时生成代码,运行时无额外开销
- Pattern Matching:编译器优化,性能与传统写法相当
- 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 - 表达力:将类型检查、转型和变量绑定合并为一步操作
- 完备性:与密封类结合,编译器可检查模式匹配的完备性
- 可维护性:简化复杂条件逻辑,提高代码可读性

365

被折叠的 条评论
为什么被折叠?



