Java 5 引入 enum 關鍵字,提供類型安全、語義清晰的常量定義方式,徹底解決傳統 int/String 常量模式的缺陷。本文系統梳理 Enum 定義、特性、六大用法模式與最佳實踐。
// int 枚舉模式 - 缺陷多多
public class Season {
public static final int SPRING = 1;
public static final int SUMMER = 2;
public static final int AUTUMN = 3;
public static final int WINTER = 4;
}
// 問題:
// 1. 非類型安全:getChineseSeason(5) 編譯通過,運行時邏輯錯誤
// 2. 可讀性差:打印輸出為數字,無語義
// 3. 脆弱性:修改常量值需重新編譯所有依賴客戶端
// 4. 無命名空間:常量污染類命名空間
public enum Season {
SPRING(1, "春季"),
SUMMER(2, "夏季"),
AUTUMN(3, "秋季"),
WINTER(4, "冬季");
private final int code;
private final String chineseName;
Season(int code, String chineseName) {
this.code = code;
this.chineseName = chineseName;
}
public int getCode() { return code; }
public String getChineseName() { return chineseName; }
}
== 比較classpublic enum Color { RED, GREEN, BLUE, YELLOW }
public enum Signal { RED, YELLOW, GREEN }
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
color = switch (color) {
case RED -> Signal.GREEN;
case YELLOW -> Signal.RED;
case GREEN -> Signal.YELLOW;
};
}
}
public enum Color {
RED("紅色", 0xFF0000),
GREEN("綠色", 0x00FF00),
BLUE("藍色", 0x0000FF);
private final String name;
private final int rgb;
Color(String name, int rgb) {
this.name = name;
this.rgb = rgb;
}
public String getName() { return name; }
public int getRgb() { return rgb; }
// 靜態查找方法
public static Color fromRgb(int rgb) {
for (Color c : values()) {
if (c.rgb == rgb) return c;
}
throw new IllegalArgumentException("Invalid RGB: " + rgb);
}
}
public enum Operation {
PLUS("+") { public double apply(double x, double y) { return x + y; } },
MINUS("-") { public double apply(double x, double y) { return x - y; } },
TIMES("*") { public double apply(double x, double y) { return x * y; } },
DIVIDE("/") { public double apply(double x, double y) { return x / y; } };
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
public abstract double apply(double x, double y);
@Override public String toString() { return symbol; }
}
// 使用
double result = Operation.PLUS.apply(3, 4); // 7.0
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour {
RED("紅色", 1),
GREEN("綠色", 2),
BLUE("藍色", 3);
private final String name;
private final int index;
Color(String name, int index) {
this.name = name;
this.index = index;
}
@Override public String getInfo() { return name; }
@Override public void print() { System.out.println(index + ": " + name); }
}
// 多態使用
Behaviour b = Color.RED;
b.print(); // 1: 紅色
public interface Food {
enum Coffee implements Food { BLACK, DECAF, LATTE, CAPPUCCINO }
enum Dessert implements Food { FRUIT, CAKE, GELATO }
}
// 使用
Food.Coffee coffee = Food.Coffee.LATTE;
Food.Dessert dessert = Food.Dessert.CAKE;
// EnumSet - 位向量實現,極致效能 SetprimaryColors = EnumSet.of(Color.RED, Color.GREEN, Color.BLUE); EnumSet all = EnumSet.allOf(Color.class); EnumSet complement = EnumSet.complementOf(primaryColors); // EnumMap - 數組實現,鍵為枚舉 Map colorNames = new EnumMap<>(Color.class); colorNames.put(Color.RED, "Red");
readResolve// 預設序列化為名稱: "RED"
// 自定義序列化為值
@JsonValue
public int getCode() { return code; }
// 反序列化支援
@JsonCreator
public static Season fromCode(@JsonProperty("code") int code) {
return Arrays.stream(values())
.filter(s -> s.code == code)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Invalid code: " + code));
}
| 陷阱 | 後果 | 解決 |
|---|---|---|
| 在建構子中啟動線程/註冊監聽器 | 類初始化死鎖、資源洩漏 | 延遲初始化或使用靜態工廠方法 |
| 大量枚舉常量導致類文件過大 | 類加載緩慢、超過 64KB 限制 | 拆分為多個枚舉或改用類+常量模式 |
| switch 缺少 default 分支 | 新增枚舉值時編譯不報錯,運行邏輯缺失 | Java 12+ switch 表達式強制窮盡;舊版加 default 拋異常 |
| 枚舉實現 Cloneable | 破壞單例語義 | Enum 最終類不可克隆,編譯器禁止 |