185. Java 模式匹配 - Java 21 新特性:Switch 的模式匹配

199 阅读3分钟

185. Java 模式匹配 - Java 21 新特性:Switch 的模式匹配

Java 21 中,Switch 模式匹配(Pattern Matching for switch 正式成为标准功能,之前曾以预览形式出现在 Java 17–20。 这个特性将 switch 表达式和 instanceof 的模式匹配结合,极大增强了 Java 的表达力与可读性。


✅ 背景与目标

Java 中的 switch 语句原本只能匹配固定值(如整数、枚举、字符串)。但在许多情况下,我们更希望根据对象的类型执行不同的逻辑,这通常需要使用冗长的 if-else 结构。

来看一个典型的例子:

Object o = ...; // 任意对象
String formatted = null;

if (o instanceof Integer i) {
    formatted = String.format("int %d", i);
} else if (o instanceof Long l) {
    formatted = String.format("long %d", l);
} else if (o instanceof Double d) {
    formatted = String.format("double %f", d);
} else {
    formatted = String.format("Object %s", o.toString());
}

☀️ 用 Switch 模式匹配重写

使用 Java 21 的 Switch 模式匹配,上面的代码可以简洁地重写为:

Object o = ...;
String formatted = switch (o) {
    case Integer i -> String.format("int %d", i);
    case Long l    -> String.format("long %d", l);
    case Double d  -> String.format("double %f", d);
    default        -> String.format("Object %s", o.toString());
};

🎯 你可以看到:

  • 每个 case 分支就像 instanceof 判断一样,自动完成类型转换。
  • 代码更简洁清晰,无需强转(casting)。

⏱ 性能优势

使用 if-else 判断,性能是 O(n),分支越多,判断次数越多。 而 switch 使用的是 表驱动机制,可以达到 O(1) 的性能(理论上更快)。


🔍 支持的 case 标签类型

在 Java 21 中,switch 支持以下 case 标签:

  • 原始整数类型:byte, short, char, int
  • 对应包装类型:Byte, Short, Character, Integer
  • String
  • 枚举类型
  • 类型模式(Type Patterns):如 case String scase Point p

🔐 受保护的 case 标签(Guarded Patterns)

我们有时不仅要匹配类型,还要加个附加条件。例如:对象是 String 且不为空。

以前只能写成 if 语句:

if (o instanceof String s && !s.isEmpty()) {
    System.out.println("非空字符串:" + s);
}

switch 中能写吗?能!

Java 21 引入了 when 子句 —— 它允许我们在 case 中添加布尔条件:

String result = switch (o) {
    case String s when !s.isEmpty() -> "Non-empty string: " + s;
    case String s                   -> "Empty string";
    default                         -> "Not a string";
};

语法解构

case 类型 模式变量 when 条件表达式 -> 返回值;

这种写法称为 guarded case label(受保护的 case 标签),比传统写法更具表达力。


📦 更多示例

示例 1:处理多种数字类型

Object o = 3.14;

String result = switch (o) {
    case Integer i       -> "整数:" + i;
    case Double d        -> "小数:" + d;
    case Number n        -> "其他数字类型:" + n;
    default              -> "不是数字";
};

示例 2:配合记录类(Record)使用

record Point(int x, int y) {}

Object o = new Point(3, 4);

String result = switch (o) {
    case Point p when p.x() == p.y() -> "这是一个对角点:" + p;
    case Point p                     -> "普通点:" + p;
    default                          -> "未知类型";
};

⚠️ 注意事项

  • case String s && !s.isEmpty() ❌ 不合法 switch 不接受直接写布尔表达式
  • 正确用法是 case String s when !s.isEmpty()
  • default 分支仍是必须的,除非已穷尽所有可能

🧠 小结

特性说明
🧩 类型匹配case 标签可是类型模式(如 case String s
🛡 受保护 case可以加上布尔条件 when 条件
⚡ 性能提升switchO(1),更快
🔍 更清晰表达减少冗余代码,提升可读性
📦 适配多种类型支持数字、字符串、枚举、记录、对象类型等

🎓 推荐实战练习

  1. 用 switch 模式匹配重构你项目中的 instanceof 判断代码
  2. 尝试组合类型 + guard 条件
  3. record 结合使用进行数据拆解