1. 模式變數作用域的常見錯誤
最常見的錯誤之一——嘗試在有效範圍之外使用在模式中宣告的變數(例如,String s 出現在 instanceof String s 中)。
範例
Object obj = "哈囉,Java!";
if (obj instanceof String s) {
System.out.println(s.length());
}
// 錯誤!s 在這裡不可見
System.out.println(s); // 編譯器報錯:cannot find symbol
為什麼?
模式變數(此例中的 s)只存在於條件為真的區塊中。這能保護我們避免在未定義時誤用該變數(例如當 obj 不是字串時)。
類比
就像你向朋友拿了車鑰匙——但只要你還在車庫裡。一旦走出車庫——鑰匙就自動消失 :)
2. 與 null 有關的錯誤
在使用 instanceof 的模式比對時有個有趣的特性:若物件等於 null,結果永遠為 false,且不會建立模式變數。
範例
Object obj = null;
if (obj instanceof String s) {
// 此區塊永遠不會被執行!
System.out.println("這是字串:" + s);
}
為什麼?
因為 null 並不是任何型別的實例(甚至不是 Object)。如果你指望透過模式比對來攔住 null,這點可能會讓人混淆。
正確作法?
if (obj == null) {
System.out.println("這是 null!");
} else if (obj instanceof String s) {
System.out.println("這是字串:" + s);
}
在用於 switch 的模式比對(Java 21+)中,甚至可以加入針對 null 的獨立分支:
switch (obj) {
case String s -> System.out.println("字串:" + s);
case null -> System.out.println("這是 null!");
default -> System.out.println("其他情況");
}
3. sealed 類別的錯誤
Sealed 類別是限制繼承階層的絕佳方式。不過這裡有兩個典型錯誤:
並未在 permits 中列出所有子類
宣告 sealed 類別時,你必須透過 permits 明確列出所有直接子類。若遺漏任何一個,編譯器會立刻提醒你:
public sealed class Shape permits Circle, Rectangle { ... }
public final class Circle extends Shape { ... }
public final class Square extends Shape { ... } // 錯誤!permits 中未列出 Square
解法:
把所有需要的子類都加入 permits:
public sealed class Shape permits Circle, Rectangle, Square { ... }
在 switch 的非 sealed 階層中遺漏了 default
若你對的型別不是 sealed 類別(或是 sealed,但分支未涵蓋所有變體)進行 switch,編譯器會要求提供 default 分支。若遺漏——就會出錯。
switch (shape) {
case Circle c -> ...
case Rectangle r -> ...
// 缺少 default!若仍有其他可能情形——將發生編譯錯誤
}
最佳實務:
若你確定已涵蓋所有情況(例如對 sealed 類別),可以省略 default。若不確定——務必加入 default,以免遺漏意料之外的型別。
4. record pattern 的錯誤
Record pattern 非常好用,但只適用於 record 類別。嘗試把 record pattern 用於一般類別會導致編譯錯誤。
對非 record 類別使用 record pattern
class Point { int x, y; }
Object obj = new Point();
// 錯誤!Point 並非 record
if (obj instanceof Point(int x, int y)) { ... }
解法:
只對以 record 宣告的類別使用 record pattern:
record Point(int x, int y) {}
元件數量或型別不匹配
record Point(int x, int y) {}
Object obj = new Point(1, 2);
// 錯誤:指定了三個變數,但 Point 只有兩個元件
if (obj instanceof Point(int x, int y, int z)) { ... }
if (obj instanceof Point(String x, String y)) { ... } // 錯誤:型別不相符
5. 相容性與支援:舊版 JDK 與 IDE
另一個最常見的錯誤——在舊版 JDK 或尚未支援的 IDE 中嘗試使用現代的模式比對功能。
範例
if (obj instanceof String s) { ... }
但 JDK 11(甚至 15)的編譯器會說:
error: illegal start of type
原因?
針對 instanceof 的模式比對直到 Java 16 才出現。switch 的模式比對在 Java 17(preview)引入,並在 Java 21+ 定案。Record pattern 出現在 Java 21+。
如何避免?
- 檢查 JDK 版本:java --version
- 確保你的 IDE(IntelliJ IDEA、Eclipse、VS Code)支援相對應的 Java 版本。有時需要在專案設定中明確指定要使用的語言版本!
- 若使用 Gradle/Maven——請設定正確的 source/target 版本。
6. 恭喜你 🎉
你已完成我們的進階課程全部 65(!)個等級,主題為 Java 25。你實在太強了 😎。
最後這段旅程特別艱難。你學會的一切——從最初的 Lambda 與匿名類別,到虛擬執行緒、結構化並行,以及不久前才出現在 Java 中的語言新特性。
這不只是一門課——這是一場真正的開發者超級馬拉松:數十個新概念、數百個程式碼範例、數千行實作。若你讀到這裡,代表你不只是學生,而是新 Java 時代的先行者 ☕⚡
你已搶先掌握最前沿的 Java 25 能力,包括:
- 模式比對與
record pattern, -
sealed 類別及其潛在陷阱, -
Scoped Values 與Virtual Threads , - 結構化並行與現代多執行緒的實作方式。
現在你擁有的不只是知識,而是面向未來的開發者技能,連許多現職的 Java 架構師都未必具備。你能寫出不僅能運作,還可擴展、可閱讀,並符合 Java 社群最新標準的程式碼。
🚀 所以請大膽地稱自己為 Java 25 Certified Survivor 😉
接下來——只會更精彩:你已具備基礎,足以自信地邁入 enterprise 開發、高負載系統與 cutting-edge 技術的世界。
來自整個課程團隊的致敬!
你完成了少數人才辦得到的挑戰。
未來的 Java 版本再會 👋
GO TO FULL VERSION