Java 列舉 (Enum)
列舉是一種特殊的類別,用來定義一組固定的常數。
基本語法
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// 使用
Day today = Day.MONDAY;
System.out.println(today); // MONDAY
在 switch 中使用
Day day = Day.SATURDAY;
switch (day) {
case MONDAY:
case TUESDAY:
case WEDNESDAY:
case THURSDAY:
case FRIDAY:
System.out.println("工作日");
break;
case SATURDAY:
case SUNDAY:
System.out.println("週末");
break;
}
列舉方法
Day day = Day.WEDNESDAY;
// name() - 取得名稱
System.out.println(day.name()); // WEDNESDAY
// ordinal() - 取得順序(從 0 開始)
System.out.println(day.ordinal()); // 2
// values() - 取得所有值
for (Day d : Day.values()) {
System.out.println(d);
}
// valueOf() - 從字串轉換
Day monday = Day.valueOf("MONDAY");
帶有屬性的列舉
public enum Size {
SMALL("S", 10),
MEDIUM("M", 15),
LARGE("L", 20);
private final String abbreviation;
private final int price;
// 建構子必須是 private
Size(String abbreviation, int price) {
this.abbreviation = abbreviation;
this.price = price;
}
public String getAbbreviation() {
return abbreviation;
}
public int getPrice() {
return price;
}
}
// 使用
Size size = Size.MEDIUM;
System.out.println(size.getAbbreviation()); // M
System.out.println(size.getPrice()); // 15
帶有方法的列舉
public enum Operation {
ADD {
@Override
public int apply(int a, int b) {
return a + b;
}
},
SUBTRACT {
@Override
public int apply(int a, int b) {
return a - b;
}
},
MULTIPLY {
@Override
public int apply(int a, int b) {
return a * b;
}
},
DIVIDE {
@Override
public int apply(int a, int b) {
return a / b;
}
};
public abstract int apply(int a, int b);
}
// 使用
int result = Operation.ADD.apply(5, 3); // 8
實作介面
public interface Printable {
void print();
}
public enum Status implements Printable {
ACTIVE {
@Override
public void print() {
System.out.println("狀態:啟用");
}
},
INACTIVE {
@Override
public void print() {
System.out.println("狀態:停用");
}
}
}
實際應用
HTTP 狀態碼
public enum HttpStatus {
OK(200, "OK"),
CREATED(201, "Created"),
BAD_REQUEST(400, "Bad Request"),
NOT_FOUND(404, "Not Found"),
INTERNAL_SERVER_ERROR(500, "Internal Server Error");
private final int code;
private final String message;
HttpStatus(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
public static HttpStatus fromCode(int code) {
for (HttpStatus status : values()) {
if (status.code == code) {
return status;
}
}
throw new IllegalArgumentException("Unknown code: " + code);
}
}
訂單狀態
public enum OrderStatus {
PENDING("待處理"),
PROCESSING("處理中"),
SHIPPED("已出貨"),
DELIVERED("已送達"),
CANCELLED("已取消");
private final String description;
OrderStatus(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
// 檢查是否可以取消
public boolean canCancel() {
return this == PENDING || this == PROCESSING;
}
}
季節
public enum Season {
SPRING, SUMMER, FALL, WINTER;
public Season next() {
return values()[(ordinal() + 1) % 4];
}
}
EnumSet 和 EnumMap
import java.util.EnumSet;
import java.util.EnumMap;
// EnumSet:列舉的高效 Set
EnumSet<Day> weekend = EnumSet.of(Day.SATURDAY, Day.SUNDAY);
EnumSet<Day> weekdays = EnumSet.range(Day.MONDAY, Day.FRIDAY);
// EnumMap:以列舉為 key 的 Map
EnumMap<Day, String> schedule = new EnumMap<>(Day.class);
schedule.put(Day.MONDAY, "會議");
schedule.put(Day.FRIDAY, "發布");
列舉 vs 常數
// 不好:使用常數
public static final int STATUS_ACTIVE = 1;
public static final int STATUS_INACTIVE = 0;
// 問題:沒有型別安全,可以傳入任何 int
// 好:使用列舉
public enum Status { ACTIVE, INACTIVE }
// 優點:型別安全、可讀性好、有方法
注意事項
- 列舉是類別,隱式繼承
java.lang.Enum - 不能繼承其他類別
- 可以實作介面
- 列舉是 final 的,不能被繼承
- 列舉的實例是單例的