痛点:老 instanceof 写法
if (obj instanceof Integer) {
Integer n = (Integer) obj; // 强转
System.out.println(n * 2);
}
instanceof 检查 + cast 各一遍,啰嗦。
instanceof 模式(Java 16+)
if (obj instanceof Integer n) { // 同时声明变量 n
System.out.println(n * 2);
}
检查 + cast 一步。n 在 if 块内是 Integer 类型可直接用。
switch 模式匹配(Java 21+ 正式)
Object obj = ...;
String desc = switch (obj) {
case Integer n -> "int: " + n;
case Long l -> "long: " + l;
case String s -> "string: " + s;
case null -> "null";
default -> "other: " + obj.getClass().getSimpleName();
};
- 类型模式 + 自动 cast
null是合法分支(不再抛 NPE)- 返回值
- 编译器穷举性检查(配 sealed 用尤其香)
配 sealed = 代数数据类型
public sealed interface Shape permits Circle, Square, Triangle {}
public record Circle(double radius) implements Shape {}
public record Square(double side) implements Shape {}
public record Triangle(double base, double height) implements Shape {}
double area(Shape s) {
return switch (s) {
case Circle c -> Math.PI * c.radius() * c.radius();
case Square sq -> sq.side() * sq.side();
case Triangle t -> t.base() * t.height() / 2;
};
}
// 不需要 default——编译器知道 sealed 子类型只这 3 个
加新子类型?比如 record Pentagon ...——所有 switch 没处理 Pentagon 的地方会编译错。逼着你处理 → 比文档约定可靠 100 倍。
解构模式(record patterns,Java 21+)
sealed interface Result<T> permits Ok, Err {}
record Ok<T>(T value) implements Result<T> {}
record Err<T>(String error) implements Result<T> {}
String describe(Result<User> r) {
return switch (r) {
case Ok<User>(User u) -> "found: " + u.name(); // 自动解构
case Err<User>(String err) -> "error: " + err;
};
}
case Ok<User>(User u) 同时检查类型 + 解构 record 字段。
嵌套也行:
record Pair<A, B>(A first, B second) {}
switch (pair) {
case Pair<String, Integer>(String s, Integer i) -> ...;
case Pair<String, Integer>(String s, null) -> ...;
}
case 守卫(when)
String classify(int n) {
return switch (n) {
case Integer i when i < 0 -> "负";
case 0 -> "零";
case Integer i when i < 10 -> "小";
case Integer i -> "大";
};
}
when 在模式后加条件——pattern 匹配 + when 守卫。
多值合并
String day(int d) {
return switch (d) {
case 1, 2, 3, 4, 5 -> "工作日";
case 6, 7 -> "周末";
default -> "?";
};
}
, 分隔多个 case。
yield 用于块体
int v = switch (n) {
case 1 -> 10;
case 2 -> {
System.out.println("computing");
yield 20; // 块体用 yield
}
default -> 0;
};
切实战:JSON-like 数据解构
sealed interface Json permits JsonObject, JsonArray, JsonString, JsonNumber, JsonBool, JsonNull {}
record JsonObject(Map<String, Json> fields) implements Json {}
record JsonArray(List<Json> items) implements Json {}
record JsonString(String value) implements Json {}
record JsonNumber(double value) implements Json {}
record JsonBool(boolean value) implements Json {}
record JsonNull() implements Json {}
String render(Json j) {
return switch (j) {
case JsonObject(Map<String, Json> fs) ->
"{" + fs.entrySet().stream()
.map(e -> "\"" + e.getKey() + "\":" + render(e.getValue()))
.collect(Collectors.joining(",")) + "}";
case JsonArray(List<Json> items) ->
"[" + items.stream().map(this::render).collect(Collectors.joining(",")) + "]";
case JsonString(String s) -> "\"" + s + "\"";
case JsonNumber(double n) -> String.valueOf(n);
case JsonBool(boolean b) -> String.valueOf(b);
case JsonNull() -> "null";
};
}
Sealed + record + pattern matching 三件套实现"代数数据类型"——以前 Java 写这种代码要 visitor pattern 上百行,现在几十行干完。
与 if-else 链对比
// ❌ 老写法
if (obj instanceof Integer) {
Integer n = (Integer) obj;
return "int: " + n;
} else if (obj instanceof String) {
String s = (String) obj;
return "string: " + s;
} else if (obj == null) {
return "null";
} else {
return "other";
}
// ✅ switch 表达式
return switch (obj) {
case Integer n -> "int: " + n;
case String s -> "string: " + s;
case null -> "null";
default -> "other";
};
紧凑 + 强类型 + 表达式(返回值)。
不支持的(Java 21 时点)
- 数组 / List 解构(Java 22+ "通配模式"还在演化)
- 字符串 / 数值 case 用模式(仍是字面量)
- Unnamed patterns
_——预览阶段
后续 Java 版本可能扩展。当前生产代码用上面这些就足够。
心智模型
学过 Rust / Scala / Kotlin 的 sealed + match——Java 21 的模式匹配是同样思路的实现。
- 数据类:record
- 封闭类型层级:sealed interface + permits
- 分发:switch with pattern + yield + exhaustiveness check
→ 下一篇 Lambda + 函数式接口