CodeGym /課程 /JAVA 25 SELF /Pattern Matching for instanceof

Pattern Matching for instanceof

JAVA 25 SELF
等級 65 , 課堂 1
開放

1. 傳統 instanceof 的問題

先來點小小回顧。在 Java 16 之前,當你需要檢查物件的型別,然後再以該型別來使用它時,通常得寫出冗長的樣板:先用 instanceof 檢查,再做明確轉型:

Object obj = ...; // 某個物件

if (obj instanceof String) {
    String s = (String) obj;
    System.out.println("字串長度: " + s.length());
}

乍看無聊,但很常見的樣板

這個模式非常常見——事件處理器、處理異質集合、含繼承的商業邏輯等。

為什麼不便

  • 重複程式碼——你得在 instanceof 與轉型處各寫一次型別。
  • 出錯風險——不小心轉成錯的型別,就會得到 ClassCastException
  • 雜訊多的程式碼——可讀性變差,尤其在多重檢查時更明顯。

2. Pattern Matching for instanceof:新語法

在 Java 16 中為 instanceof 加入了模式比對(pattern matching)。現在可以在檢查型別的同時,直接宣告對應型別的變數,該變數在 if 分支內可用。

新語法

if (obj instanceof String s) {
    // s 已經是字串了!
    System.out.println("字串長度: " + s.length());
}
  • instanceof 的型別之後寫上新變數名稱:String s
  • 該變數只在條件為真的區塊中可用。
  • 不需要寫明確轉型 (String)——編譯器會保證。

魔法在哪裡? 編譯器會檢查型別,若符合,就「解構」出所需型別的變數;否則區塊不會執行。

實際程式碼中的樣子

Object obj = "嗨,Java 16+!";

if (obj instanceof String s) {
    System.out.println("大寫: " + s.toUpperCase());
} else {
    System.out.println("這不是字串!");
}

3. 安全與可讀性:為什麼這很棒

杜絕 ClassCastException 錯誤

Object obj = 123;
// String s = (String) obj; // 砰!例外。

使用模式比對時,只有在型別檢查通過才會建立變數——不會出現「錯誤轉型」。

程式碼更短、更易懂
兩行變一行。雜訊更少——更易讀、也更容易維護。

範例:處理不同型別

public static void printInfo(Object obj) {
    if (obj instanceof String s) {
        System.out.println("字串長度 " + s.length());
    } else if (obj instanceof Integer i) {
        System.out.println("整數: " + (i + 1));
    } else {
        System.out.println("未知型別: " + obj);
    }
}

4. 使用範例與注意事項

檢查多種型別

Object value = ...;

if (value instanceof String s) {
    System.out.println("這是字串: " + s);
} else if (value instanceof Number n) {
    System.out.println("這是數字: " + n);
} else {
    System.out.println("其他東西: " + value);
}

與 null 的使用
若物件為 null,則 instanceof 一定回傳 false——不會出現 NPE,但區塊也不會執行。

Object obj = null;

if (obj instanceof String s) {
    // 如果 obj == null,此區塊永遠不會執行
    System.out.println("字串: " + s);
} else {
    System.out.println("obj 是 null 或不是字串");
}

在繼承下的 pattern matching

class Animal {}
class Dog extends Animal {
    void bark() { System.out.println("汪!"); }
}

Animal a = new Dog();

if (a instanceof Dog d) {
    d.bark(); // 可以不轉型就呼叫 Dog 的方法!
}

提醒:檢查順序很重要,請由較具體到較一般,否則較窄的檢查可能不會匹配。

比較:舊方法 vs 新方法

舊方法 新方法(pattern matching)
if (obj instanceof Cat) {
    Cat c = (Cat) obj;
    c.meow();
}
if (obj instanceof Cat c) {
    c.meow();
}

5. instanceof 的 pattern matching 限制

  • 變數的可見範圍。 樣式中建立的變數只在檢查為真的分支中可見。
if (obj instanceof String s) {
    System.out.println(s); // s 可用
}
// System.out.println(s); // 錯誤!此處看不到 s
  • 不能在同一個條件宣告多個不同型別的變數。
// 編譯錯誤:
if (obj instanceof String s || obj instanceof Integer i) {
    // ...
}
  • 需要 Java 16+。 在更舊版本的 JDK 上不支援新語法。

6. 實用範例(基於簡單應用)

想像一個簡單的 Task Manager,包含不同的任務型別。

類別

class Task {
    String title;
    public Task(String title) { this.title = title; }
}

class BugTask extends Task {
    int severity;
    public BugTask(String title, int severity) {
        super(title);
        this.severity = severity;
    }
}

class FeatureTask extends Task {
    String feature;
    public FeatureTask(String title, String feature) {
        super(title);
        this.feature = feature;
    }
}

利用 pattern matching 進行處理

public static void processTask(Task t) {
    if (t instanceof BugTask bug) {
        System.out.println("Bug: " + bug.title + ",嚴重度: " + bug.severity);
    } else if (t instanceof FeatureTask feature) {
        System.out.println("Feature: " + feature.title + ",模組: " + feature.feature);
    } else if (t instanceof Task task) {
        System.out.println("一般任務: " + task.title);
    }
}

7. 實用細節

表格:instanceof 的 pattern matching——優缺點

優點 缺點/限制
程式碼更少、可讀性更高 需要 Java 16+
不會有 ClassCastException 風險 變數只在 if 區塊內可見
編譯期型別安全 無法在同一個條件同時處理多種型別
便於處理繼承 在舊版 IDE 與建置中可能不支援
適用於任何類別

視覺化流程:instanceof 的 pattern matching 如何運作

+---------------------------+
|      Object obj           |
+---------------------------+
            |
            v
  if (obj instanceof Type t)
            |
      是            否
   (true)        (false)
    |               |
    v               v
 t 可用         t 不存在
  (可存取)        (無法存取)

8. 使用 pattern matching for instanceof 的常見錯誤

錯誤 1:嘗試在 if 區塊外使用變數。 在樣式中宣告了變數,但一離開該區塊,變數就不存在了。編譯器會合理地抱怨:「s 是誰?」

錯誤 2:期待 instanceofnull 也會成立。 如果物件為 nullinstanceof 條件必為假,變數也不會建立。必要時請另外處理 null

錯誤 3:在舊版 JDK/IDE 使用新語法。 在 Java 11 及以下版本,instanceof 的模式比對不可用——會出現語法錯誤。請檢查 JDK 版本。

錯誤 4:混淆作用域。 樣式中建立的變數只在檢查為真的分支可用;在其外部並不存在。

錯誤 5:期待同時支援多種型別。 不能在同一個條件中同時宣告兩個不同型別的變數:if (obj instanceof String s || obj instanceof Integer i)——這樣不行。每個型別都要各自檢查。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION