整理Effective Java書中Item 36: Use EnumSet instead of bit fields心得筆記

主旨

在 Java 裡,用 intlong 表示多種布林選項的做法已經過時了,這種設計方式可讀性差又容易出錯。現在有更好的選擇 —— EnumSet。它不但語意清楚、效能高,而且更安全、好維護。

點出問題:傳統寫法的缺點

假設你要開發一個露營網站,使用者可以選擇多種活動(像是烤肉、划船、夜間觀星、登山健行等)。如果你用傳統的位元欄位來記錄活動選項,可能會這樣寫:

public class ActivityOld {
    public static final int BBQ = 1 << 0;
    public static final int BOATING = 1 << 1;
    public static final int STARGAZING = 1 << 2;
    public static final int HIKING = 1 << 3;
}

// 使用方式:
int selectedActivities = ActivityOld.BBQ | ActivityOld.HIKING;

問題在哪裡?

  • 看不懂 1 << 2 是什麼活動
  • 要新增活動要小心選位元,超過 32/64 還要換型別
  • 沒有型別安全檢查,可能誤用錯值
  • 可讀性與維護性差

範例:用 EnumSet 改寫更清楚

public enum Activity {
    BBQ, BOATING, STARGAZING, HIKING
}

public class CampReservation {
    private EnumSet<Activity> activities;

    public CampReservation(EnumSet<Activity> activities) {
        this.activities = activities;
    }

    public boolean includes(Activity activity) {
        return activities.contains(activity);
    }

    public void printActivities() {
        for (Activity activity : activities) {
            System.out.println("參加活動:" + activity);
        }
    }
}

使用方式:

CampReservation reservation = new CampReservation(EnumSet.of(
    Activity.BBQ, Activity.HIKING));

reservation.printActivities();
// 輸出:
// 參加活動:BBQ
// 參加活動:HIKING

劃重點

  • EnumSet 是針對 enum 設計的高效集合,底層就是用位元實作,但不暴露實作細節。
  • 可讀性與型別安全性都比 int 常數高。
  • 新增活動時,只要在 enum 裡加一項,其他程式不用動。
  • 若活動超過 64 個,EnumSet 也能自動從 RegularEnumSet 轉成 JumboEnumSet 處理,不需手動改型別。

小結

如果你需要表示「多種 enum 狀態可同時成立」,請不要再用 intlong 自己拼位元欄位了。EnumSet 提供了更簡單、更穩、更直覺的解法,不只能讓程式碼更清楚,也能減少錯誤與未來維護負擔。未來遇到類似需求時,第一個該想到的就是 EnumSet