模式匹配(Pattern Matching)

Java 16 引入了模式匹配,用来简化类型检查和类型转换的代码。

以前我们写代码,instanceof 检查后还要手动强制转换:

// 以前
if (obj instanceof String) {
    String s = (String) obj;  // 还要再转一次
    System.out.println(s.length());
}

现在可以这样写:

// Java 16+
if (obj instanceof String s) {
    System.out.println(s.length());  // s 已经声明好了
}

今天我们就来把模式匹配彻底讲透。

一、instanceof 模式匹配

1.1 Java 16+:类型测试模式

Object obj = getSomeObject();

// 以前:if + instanceof + 强制转换
if (obj instanceof String) {
    String s = (String) obj;
    System.out.println(s.length());
}

// Java 16+:直接在 instanceof 中声明变量
if (obj instanceof String s) {
    System.out.println(s.length());  // s 已经是 String 类型
}

1.2 模式变量的作用域

Object obj = "Hello";

if (obj instanceof String s) {
    System.out.println(s.toUpperCase());  // ✅ s 在这里可见
}

System.out.println(s.toUpperCase());  // ❌ 编译错误!s 不在这里

1.3 配合条件

Object obj = "Hello World";

// 带条件的模式匹配
if (obj instanceof String s && s.length() > 5) {
    System.out.println("Long string: " + s);
}

// 或者用 || 但要小心
if (obj instanceof String s || s.length() > 5) {
    // ❌ 这里 s 可能未定义,因为 || 可能短路
}

二、Record Pattern(记录模式)

2.1 基本用法

record Point(int x, int y) {}

// 以前
if (obj instanceof Point) {
    Point p = (Point) obj;
    int sum = p.x() + p.y();
}

// Java 16+:直接提取字段
if (obj instanceof Point(int x, int y)) {
    int sum = x + y;  // x 和 y 已经提取出来了
}

2.2 嵌套 Record 模式

record Rect(Point topLeft, Point bottomRight) {}

Rect rect = new Rect(new Point(0, 0), new Point(10, 10));

// 嵌套提取
if (rect instanceof Rect(Point(int x1, int y1), Point(int x2, int y2))) {
    System.out.println("Width: " + (x2 - x1));
    System.out.println("Height: " + (y2 - y1));
}

2.3 Record + instanceof

sealed interface Response permits Success, Error {}

record Success(String data) implements Response {}
record Error(String message) implements Response {}

Response r = getResponse();

// 直接匹配并提取
if (r instanceof Success(String data)) {
    System.out.println("Success: " + data);
} else if (r instanceof Error(String msg)) {
    System.out.println("Error: " + msg);
}

三、Switch 模式匹配

3.1 Java 21+:Switch 表达式模式匹配

// Java 21+:Switch 支持模式匹配
String describe(Object obj) {
    return switch (obj) {
        case null -> "null";
        case Integer i -> "Integer: " + i;
        case String s -> "String: " + s;
        case Point(int x, int y) -> "Point at (" + x + ", " + y + ")";
        default -> "Unknown";
    };
}

3.2 Guard Pattern(带条件的模式)

String describe(Object obj) {
    return switch (obj) {
        case Integer i when i > 0 -> "Positive: " + i;
        case Integer i when i < 0 -> "Negative: " + i;
        case Integer i -> "Zero";
        case String s when s.isEmpty() -> "Empty string";
        case String s -> "Non-empty: " + s;
        default -> "Other";
    };
}

3.3 Null 处理

String describe(Object obj) {
    return switch (obj) {
        case null -> "It's null!";  // null 要单独处理
        case String s -> "String: " + s;
        default -> "Other";
    };
}

四、Array Pattern(数组模式)

4.1 基本用法

Object arr = new int[] {1, 2, 3};

// 匹配数组并提取长度
if (arr instanceof int[] { int length : l }) {
    System.out.println("Array length: " + l);
}

4.2 嵌套数组模式

int[][] matrix = { {1, 2}, {3, 4} };

if (matrix instanceof int[][] { int[] { int a, int b }, int[] { int c, int d } }) {
    System.out.println(a + ", " + b + ", " + c + ", " + d);
}

五、【直观类比】

【直观类比】

模式匹配就像"拆快递":

┌─────────────────┐
│   包裹(Object)  │
│  ┌───────────┐  │
│  │ 打开后发现 │  │
│  │ 是一本书   │  │
│  └───────────┘  │
└─────────────────┘

以前:先猜是什么,再拆,再转类型
      if (obj instanceof Book) { Book b = (Book) obj; ... }

现在:一边拆一边声明
      if (obj instanceof Book(String title, String author) b) {
          // 拆开后直接知道是 Book,作者是 author,书名是 title
      }

六、实际应用

6.1 简化处理逻辑

// 以前:复杂的 if-else
void printSummary(Object item) {
    if (item instanceof Book) {
        Book b = (Book) item;
        System.out.println("Book: " + b.title());
    } else if (item instanceof Movie) {
        Movie m = (Movie) item;
        System.out.println("Movie: " + m.title());
    } else if (item instanceof Song) {
        Song s = (Song) item;
        System.out.println("Song: " + s.title());
    }
}

// 现在:简洁清晰
void printSummary(Object item) {
    if (item instanceof Book(String title, String author)) {
        System.out.println("Book: " + title + " by " + author);
    } else if (item instanceof Movie(String title, int duration)) {
        System.out.println("Movie: " + title + " (" + duration + "min)");
    } else if (item instanceof Song(String title, String artist)) {
        System.out.println("Song: " + title + " - " + artist);
    }
}

6.2 模式匹配 + Switch

String getTrafficInfo(Object transport) {
    return switch (transport) {
        case Car(String brand, int seats) when seats > 5 -> 
            "Large car: " + brand;
        case Car(String brand, int seats) -> 
            "Compact car: " + brand;
        case Bike(String brand) -> 
            "Bike: " + brand;
        case Bus(int capacity, String route) -> 
            "Bus " + route + " (capacity: " + capacity + ")";
        case null -> "No transport";
        default -> "Unknown transport";
    };
}

七、注意事项

7.1 变量遮蔽

String s = "outer";

if (obj instanceof String s) {  // ❌ 编译错误:s 重复定义
    // ...
}

7.2 顺序很重要

if (obj instanceof String s || obj instanceof Integer i) {
    // ❌ 如果 String 在前且匹配,后面的 Integer 检查不会执行
}

// ✅ 明确的顺序
if (obj instanceof Integer i) {
    // 处理 Integer
} else if (obj instanceof String s) {
    // 处理 String
}

7.3 Switch 的穷尽检查

// Sealed interface + Switch = 编译器检查
sealed interface Shape permits Circle, Rectangle {}

String describe(Shape s) {
    return switch (s) {
        case Circle(double r) -> "Circle r=" + r;
        case Rectangle(double w, double h) -> "Rect " + w + "x" + h;
        // ✅ 编译器知道只有这两种,不需要 default
    };
}

八、面试追问链

第一层:基础用法

面试官问:"instanceof 模式匹配怎么用?"

在 instanceof 判断后直接声明变量,如 if (obj instanceof String s)。s 的作用域只在 if 块内。

第二层:Record 模式

面试官问:"Record 模式是什么?"

obj instanceof Point(int x, int y) 可以直接提取 Point 的 x 和 y 字段,不需要手动转型。

第三层:Switch 模式匹配

面试官问:"Switch 表达式支持模式匹配吗?"

Java 21+ 支持。可以在 switch 的 case 中使用模式,如 case Integer i ->case Point(int x, int y) ->

【学习小结】

  • instanceof 模式匹配:在判断时声明变量
  • Record 模式:直接提取字段
  • Switch 模式匹配:case 使用模式
  • Guard 模式:带条件的模式
  • 配合 sealed class 有穷尽检查