Java 初學者常見困擾:為什麼不用 int?改用 enum 讓你的程式更安全【Thinking in Java筆記(4-7)】

Java 初學者常見困擾:為什麼不用 int?改用 enum 讓你的程式更安全【Thinking in Java筆記(4-7)】
Photo by orbtal media / Unsplash

你是否曾經在寫 Java 程式的時候,為了定義一堆固定的常數而搞得心煩氣躁?像是辣度等級、交通燈號、付款方式等等,只好用 intString 來湊合著用,然後還得自己驗證值對不對,感覺自己像個沒日沒夜守在輸入口的保全

別怕,enum 來了,從 Java SE5 開始,它正式成為語言的一部分,專門解決「我只想要這幾個選項,拜託別給我亂輸入」的問題

列舉是什麼?你可以想成是一份選單

先來個基本的例子:

public enum Spiciness {
  NOT, MILD, MEDIUM, HOT, FLAMING
}

這樣一來,你就有了五種固定的辣度。每個辣度都像是一個菜單上的選項,不能亂加不能亂改,非常有紀律

這背後其實是 Java 編譯器幫你偷偷生出來的一個類別,每個選項(NOT, MILD 等)都是它的實例,而且還會偷偷標上一個從 0 開始的號碼,叫做「序數」(ordinal)

怎麼用?我們做個辣味檢查員

public class EnumOrder {
  public static void main(String[] args) {
    for(Spiciness s : Spiciness.values())
      System.out.println(s + ", ordinal " + s.ordinal());
  }
} /* Output:
NOT, ordinal 0
MILD, ordinal 1
MEDIUM, ordinal 2
HOT, ordinal 3
FLAMING, ordinal 4
*/
  • values() 是編譯器幫你生出來的方法,會吐出所有辣度
  • ordinal() 就是那個偷偷加上的序號

你可以把 values() 想成是一份辣椒測試名單,ordinal() 則是他們在辣味排行榜上的名次

列舉的進階特性

雖然 enum 看起來只是把幾個常數塞進一個列表,但它其實背後非常有戲。這不是個死板的列表,而是一個功能齊全的類別!沒錯,每個 enum 都自動繼承自 java.lang.Enum,所以它能幹很多你平常會讓類別做的事

你可以:

  • 給每個列舉值加上建構子、欄位(屬性)、方法,甚至覆寫方法
  • 把 enum 放進設計模式裡使用,例如單例模式(Singleton)或狀態模式(State Pattern)

enum 就像 RPG 遊戲裡的角色職業系統。每個列舉值都是一個職業(像是戰士、法師、牧師),都有自己的名稱(列舉值),專屬的技能(方法),還可能有特殊能力值(屬性)。你不只知道有哪些職業,還能根據職業做出對應的行動

public enum Role {
  WARRIOR("Tank", 150),
  MAGE("DPS", 80),
  PRIEST("Healer", 100);

  private final String roleType;
  private final int baseHP;

  Role(String roleType, int baseHP) {
    this.roleType = roleType;
    this.baseHP = baseHP;
  }

  public String getRoleType() {
    return roleType;
  }

  public int getBaseHP() {
    return baseHP;
  }

  public void useSkill() {
    switch (this) {
      case WARRIOR -> System.out.println("Shield Slam!");
      case MAGE -> System.out.println("Fireball!");
      case PRIEST -> System.out.println("Heal!");
    }
  }
}

你也可以寫一個小程式來走訪每個角色,輸出他們的屬性與技能,就像是一個角色面試大會:

public class RoleTest {
  public static void main(String[] args) {
    for (Role role : Role.values()) {
      System.out.println(role.name());
      System.out.println("Type: " + role.getRoleType());
      System.out.println("Base HP: " + role.getBaseHP());
      System.out.print("Skill: ");
      role.useSkill();
      System.out.println();
    }
  }
}

這樣一來,我們不只是把角色分類,更能給每個角色定義屬性(像是血量)、行為(像是使用技能),然後用迴圈或條件判斷等基本語法,針對不同角色做出不同處理。例如你可以用 switch(role) 來依照職業做不同的遊戲邏輯判斷,或者在 for 迴圈中一一列出角色資訊。這讓 enum 不只是靜態常數表,而是一群能被「呼叫」與「反應」的智能角色

與 switch 配合,一拍即合

接下來來點實用的例子:你要做一個 Burrito(墨西哥捲餅)點餐系統,根據辣度顯示不同訊息

public class Burrito {
  Spiciness degree;
  public Burrito(Spiciness degree) { this.degree = degree;}
  public void describe() {
    System.out.print("This burrito is ");
    switch(degree) {
      case NOT:    System.out.println("not spicy at all.");
                   break;
      case MILD:
      case MEDIUM: System.out.println("a little hot.");
                   break;
      case HOT:
      case FLAMING:
      default:     System.out.println("maybe too hot.");
    }
  }	
  public static void main(String[] args) {
    Burrito
      plain = new Burrito(Spiciness.NOT),
      greenChile = new Burrito(Spiciness.MEDIUM),
      jalapeno = new Burrito(Spiciness.HOT);
    plain.describe();
    greenChile.describe();
    jalapeno.describe();
  }
} /* Output:
This burrito is not spicy at all.
This burrito is a little hot.
This burrito is maybe too hot.
*/

這樣做的好處是:

  • switch 搭配 enum 可以明確列出每種狀況
  • 如果將來新增辣度(例如 "NUCLEAR"),你會馬上知道哪些地方沒處理

這就像你開了一家 Burrito 店,每一種辣度你都安排了不同的店員介紹說詞,不會有顧客點到一個辣度結果沒人接待的情況

還能幹嘛?不只是常數表而已

因為 enum 是類別,它可以:

  • 實作介面(等你學到介面再回來看這句)
  • 寫方法與建構子,讓每個列舉值有自己的行為與屬性
  • 覆寫 toString() 來自訂顯示文字

這些特性讓 enum 遠比單純常數表來得強大,甚至可以當作你在邏輯中負責「根據情況做不同事」的角色小幫手

雖然 enum 能做到像設計模式那種進階應用,但這裡我們先專注在它最實用的好處:寫起來更安全、更清楚、更不容易出錯。

為什麼你應該用 enum?

  1. 類型安全:不能亂塞東西,只能用你定義過的選項。
  2. 可讀性好Spiciness.HOT3 好懂太多。
  3. 更容易維護:加辣度?只改 enum 就好。

結語:把 enum 當成你程式裡的守門員

學會使用 enum,就等於給你的程式加上一道強而有力的防線——它確保你只能用對的選項,拒絕所有奇怪的輸入,不讓程式進入「我怎麼又用錯值了」的地獄

它不像 intString 那麼容易亂用,卻比你想像的靈活:可以加屬性、寫方法、控制行為邏輯,甚至搭配 switch 把邏輯整理得清清楚楚

當你發現程式裡某個欄位「只應該有固定幾種選擇」,那就是 enum 該出場的時候

初學者學會 enum,會讓程式更穩定、維護起來也更不容易崩潰。不是炫技,是為了讓你少 debug 幾個小時