Pattern Matching
模式匹配让你写更少的代码,做更少的事。
JDK 16 正式引入了 instanceof 的模式匹配,JDK 17 增强了 switch 的模式匹配。
instanceof 的模式匹配
以前 vs 现在
java
Object obj = "Hello";
// 以前:需要强制转换
if (obj instanceof String) {
String s = (String) obj; // 多余的代码
System.out.println(s.length());
}
// 现在:一步到位
if (obj instanceof String s) {
System.out.println(s.length()); // s 自动是 String 类型
}作用域规则
模式变量 s 只在 true 分支有效:
java
if (!(obj instanceof String s)) {
// 这里 s 不可用
System.out.println("not a string");
} else {
// 这里 s 可用
System.out.println(s.length());
}
// 或者
if (obj instanceof String s) {
// 这里 s 可用
System.out.println(s.length());
}
// 这里 s 不可用结合否定
java
if (!(obj instanceof String s)) {
// obj 不是 String
return;
}
// obj 是 String,s 在这里可用
System.out.println(s.length());switch 的模式匹配(JDK 21)
基本语法
java
// JDK 21+
Object obj = 42;
String result = switch (obj) {
case Integer i -> "整数: " + i;
case String s -> "字符串: " + s;
case null -> "null";
default -> "其他";
};带条件的模式
java
String describe(Object obj) {
return switch (obj) {
case Integer i when i > 0 -> "正整数: " + i;
case Integer i -> "整数: " + i;
case String s when s.length() > 5 -> "长字符串: " + s;
case String s -> "字符串: " + s;
case null -> "null";
default -> "其他: " + obj.getClass().getSimpleName();
};
}when 子句叫模式守卫(Pattern Guard)。
Record 模式
java
record Point(int x, int y) {}
record Line(Point start, Point end) {}
// 嵌套解构
void printLine(Line line) {
String desc = switch (line) {
case Line(Point(int x1, int y1), Point(int x2, int y2)) ->
"线段从(" + x1 + "," + y1 + ")到(" + x2 + "," + y2 + ")";
};
System.out.println(desc);
}完整示例
场景一:类型安全的计算器
java
public class Calculator {
public static Expr create(double value) {
return new Const(value);
}
public static Expr create(String op, Expr left, Expr right) {
return switch (op) {
case "+" -> new Add(left, right);
case "-" -> new Sub(left, right);
case "*" -> new Mul(left, right);
case "/" -> new Div(left, right);
default -> throw new IllegalArgumentException("Unknown op: " + op);
};
}
public static double eval(Expr expr) {
return switch (expr) {
case Const c -> c.value();
case Add a -> eval(a.left()) + eval(a.right());
case Sub s -> eval(s.left()) - eval(s.right());
case Mul m -> eval(m.left()) * eval(m.right());
case Div d -> eval(d.left()) / eval(d.right());
};
}
// 表达式接口和实现
public sealed interface Expr permits Const, Add, Sub, Mul, Div {}
public record Const(double value) implements Expr {}
public record Add(Expr left, Expr right) implements Expr {}
public record Sub(Expr left, Expr right) implements Expr {}
public record Mul(Expr left, Expr right) implements Expr {}
public record Div(Expr left, Expr right) implements Expr {}
public static void main(String[] args) {
// (2 + 3) * 4 = 20
Expr expr = create("*",
create("+", create(2), create(3)),
create(4)
);
System.out.println(eval(expr)); // 20.0
}
}场景二:JSON 解析
java
public class JsonDemo {
public static String describe(Object json) {
return switch (json) {
case null -> "null";
case Boolean b -> "布尔: " + b;
case Number n -> "数字: " + n;
case String s -> "字符串: " + s;
case List<?> list -> "数组,长度=" + list.size();
case Map<?, ?> map -> "对象,键=" + map.size();
default -> "未知类型";
};
}
public static void main(String[] args) {
System.out.println(describe("hello")); // 字符串: hello
System.out.println(describe(42)); // 数字: 42
System.out.println(describe(List.of(1, 2))); // 数组,长度=2
}
}与 Sealed Classes 配合
模式匹配和密封类是天生一对:
java
public sealed interface Shape permits Circle, Rectangle, Square {}
public record Circle(double radius) implements Shape {}
public record Rectangle(double width, double height) implements Shape {}
public record Square(double side) implements Shape {}
// 编译器确保穷尽
public double area(Shape shape) {
return switch (shape) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Rectangle r -> r.width() * r.height();
case Square s -> s.side() * s.side();
};
}常用模式
类型模式
java
if (obj instanceof String s) {
// s 是 String
}记录模式
java
if (obj instanceof Point(int x, int y)) {
System.out.println(x + y);
}数组模式
java
if (obj instanceof String[] arr && arr.length > 0) {
System.out.println(arr[0]);
}逻辑组合
java
if (obj instanceof String s && !s.isBlank()) {
// s 非空字符串
}小结
模式匹配让代码更简洁:
java
// ❌ 以前
if (obj instanceof String) {
String s = (String) obj;
// 使用 s
}
// ✅ 现在
if (obj instanceof String s) {
// 直接使用 s
}
// ✅ JDK 21+ switch
return switch (obj) {
case Integer i -> "整数: " + i;
case String s -> "字符串: " + s;
case null -> "null";
default -> "其他";
};结合 Sealed Classes 使用,编译器能确保穷尽性,代码既简洁又安全。
