CodeGym /課程 /JAVA 25 SELF /解析新功能中的常見錯誤

解析新功能中的常見錯誤

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

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 版本再會 👋

1
問卷/小測驗
新語言功能,等級 65,課堂 4
未開放
新語言功能
新語言功能
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION