首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java Enum 枚舉類型完全指南:進階用法、字串轉換與最佳實踐

     編輯:Java 相關知識

為什麼選擇 Enum?

  • 類型安全:編譯期限制合法值,避免字串/整數常量的任意傳入。
  • 單例保證:每個枚舉常量在 JVM 中唯一,== 比較安全高效。
  • 豐富行為:可攜帶欄位、方法、實作介面,將業務邏輯封裝在枚舉內部。
  • IDE 友好:自動完成、重構支援、switch 完整性檢查。

基礎定義與擴展

public enum OrderStatus {
    PENDING("待付款", 1),
    PAID("已付款", 2),
    SHIPPED("已發貨", 3),
    COMPLETED("已完成", 4),
    CANCELLED("已取消", 5);

    private final String displayName;
    private final int code;

    OrderStatus(String displayName, int code) {
        this.displayName = displayName;
        this.code = code;
    }
    public String getDisplayName() { return displayName; }
    public int getCode() { return code; }

    // 靜態查找輔助
    private static final Map CODE_MAP = Arrays.stream(values())
            .collect(Collectors.toMap(OrderStatus::getCode, s -> s, (a, b) -> a));
    public static OrderStatus fromCode(int code) {
        return CODE_MAP.getOrDefault(code, PENDING);
    }
}

字串/外部資料轉枚舉:核心技巧

1. 標準 valueOf (區分大小寫、必須精確匹配)

OrderStatus s = OrderStatus.valueOf("PAID"); // OK
OrderStatus s = OrderStatus.valueOf("paid"); // IllegalArgumentException

2. 忽略大小寫轉換

public static OrderStatus fromStringIgnoreCase(String name) {
    if (name == null) return null;
    for (OrderStatus s : values()) {
        if (s.name().equalsIgnoreCase(name)) return s;
    }
    return null; // 或拋出異常
}

3. 資料庫/前端代碼映射 (code/字串雙向)

// 已在枚舉內建立 CODE_MAP,支援 fromCode(int)
int dbCode = 3;
OrderStatus status = OrderStatus.fromCode(dbCode); // SHIPPED

4. 駝峰/下劃線命名風格自動轉換

public enum UserAction {
    SAVE_USER, GET_USER_BY_ID, DELETE_USER_BY_ID;

    public String toCamelCase() {
        return Arrays.stream(name().split("_"))
                .map(s -> s.substring(0,1).toUpperCase() + s.substring(1).toLowerCase())
                .collect(Collectors.joining());
    }
    // SAVE_USER -> SaveUser
}

實作介面:行為封裝

public interface DiscountStrategy {
    BigDecimal calculate(BigDecimal amount);
}

public enum MemberLevel implements DiscountStrategy {
    NORMAL("普通會員") { public BigDecimal calculate(BigDecimal a) { return a; } },
    SILVER("銀卡") { public BigDecimal calculate(BigDecimal a) { return a.multiply(new BigDecimal("0.95")); } },
    GOLD("金卡") { public BigDecimal calculate(BigDecimal a) { return a.multiply(new BigDecimal("0.90")); } },
    DIAMOND("鑽石") { public BigDecimal calculate(BigDecimal a) { return a.multiply(new BigDecimal("0.85")); } };

    private final String desc;
    MemberLevel(String desc) { this.desc = desc; }
    public String getDesc() { return desc; }
}

// 使用
BigDecimal payable = MemberLevel.GOLD.calculate(new BigDecimal("1000")); // 900

進階:EnumMap / EnumSet 高效集合

// EnumMap: key 為枚舉,底層陣列,極快
EnumMap countMap = new EnumMap<>(OrderStatus.class);
countMap.put(OrderStatus.PAID, 100);

// EnumSet: 位向量實作,集合運作極快
EnumSet activeStatuses = EnumSet.of(OrderStatus.PAID, OrderStatus.SHIPPED);
activeStatuses.contains(OrderStatus.PAID); // true

序列化與反射注意事項

  • 枚舉序列化僅儲存名稱,反序列化自動調用 valueOf,天然防偽造、單例不破壞。
  • Enum.valueOf(Class<T>, String) 為反射入口,性能優於一般反射。

最佳實踐清單

  1. 枚舉常量名全大寫下劃線 (PENDING_PAYMENT)。
  2. 欄位宣告 private final,提供 getter,避免 setter** (破壞單例線程安全)。
  3. 複雜查找邏輯建立 static final Map 快取,靜態區塊初始化。
  4. switch 盡量無 default,新增枚舉時編譯器提醒漏處理 case。
  5. 大量枚舉常量時考慮拆分為多個枚舉類別,避免類膨脹。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved