簡(jiǎn)介
枚舉類型是一種使用一組預(yù)定義的常量表示的一種特殊數(shù)據(jù)類型。enum關(guān)鍵字在 java5 中引入,所有的枚舉類默認(rèn)都集成自java.lang.Enum類。
//基本寫(xiě)法
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
枚舉與常量比較
- 優(yōu)點(diǎn)
- 可讀性更高
- 編譯時(shí)檢查減少代碼錯(cuò)誤(相對(duì)于基本數(shù)據(jù)類型的常量)
- 表現(xiàn)力更強(qiáng)(相對(duì)于基本數(shù)據(jù)類型的常量)
- 使用 == 對(duì)枚舉進(jìn)行比較提供編譯時(shí)和運(yùn)行時(shí)的安全性
- 缺點(diǎn)
- 增加類的數(shù)目
- 數(shù)據(jù)轉(zhuǎn)換麻煩
public class Date {
private Day day;
public static void main(String[] args) {
Date today = new Date();
//可能會(huì)出NPE
if (today.getDay().equals(Day.FRIDAY)) {
//todo
}
//使用==保證運(yùn)行時(shí)安全
if (today.getDay() == Day.FRIDAY) {
//todo
}
//比較會(huì)得到true
if (today.getDay().equals(Color.FRIDAY)) {
//todo
}
//編譯報(bào)錯(cuò)保證編譯檢查安全
//if (today.getDay() == Color.FRIDAY) {
//todo
//}
}
public Day getDay() {
return day;
}
public void setDay(Day day) {
this.day = day;
}
}
enum Color {
RED,GREEN,FRIDAY
}
使用場(chǎng)景與實(shí)例
- 在switch中使用
public static boolean isWeekend(Day day) {
switch (day) {
case SATURDAY:
case SUNDAY:
return true;
default:
return false;
}
}
- 枚舉類型增加屬性和方法
public enum RepayMethod {
BULLET_REPAYMENT(1, "一次性還款"),
INTEREST(2, "先息后本"),
EQUAL_INSTALLMENT(4, "等額本息"),
EQUAL_PRINCIPAL(8, "等額本金");
private Integer code;
private String msg;
private RepayMethod(Integer type, String msg) {
this.code = type;
this.msg = msg;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
- java8 lambda使用枚舉
public class Loan {
private Long id;
private RepayMethod repayMethod;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public RepayMethod getRepayMethod() {
return repayMethod;
}
public void setRepayMethod(RepayMethod repayMethod) {
this.repayMethod = repayMethod;
}
public static List<Loan> groupByRepayMethod(List<Loan> list, RepayMethod repayMethod) {
return list.stream().filter(loan -> repayMethod == loan.repayMethod).collect(Collectors.toList());
}
}
- EnumSet
EnumSet 是一種專門(mén)為枚舉類型所設(shè)計(jì)的 Set 類型。與HashSet相比,由于使用了內(nèi)部位向量表示,因此它是特定 Enum 常量集的非常有效且緊湊的表示形式。EnumSet 是抽象類,其有兩個(gè)實(shí)現(xiàn):RegularEnumSet (小于等于64個(gè)元素使用)、JumboEnumSet,選擇哪一個(gè)取決于實(shí)例化時(shí)枚舉中常量的數(shù)量。使用EnumSet的of方法來(lái)構(gòu)建EnumSet。
private static EnumSet<RepayMethod> MULTIPLE_PERIOD_REPAY_METHOD = EnumSet.of(INTEREST,EQUAL_INSTALLMENT,EQUAL_PRINCIPAL);
public static boolean isMultiplePeriod(RepayMethod repayMethod) {
return MULTIPLE_PERIOD_REPAY_METHOD.contains(repayMethod);
}
- EnumMap
EnumMap是一個(gè)專門(mén)化的映射實(shí)現(xiàn),用于將枚舉常量用作鍵。與對(duì)應(yīng)的 HashMap 相比,它是一個(gè)高效緊湊的實(shí)現(xiàn),并且在內(nèi)部表示為一個(gè)數(shù)組
public static EnumMap<RepayMethod, List<Loan>> groupByRepayMethod(List<Loan> list) {
EnumMap<RepayMethod, List<Loan>> map = new EnumMap(RepayMethod.class);
for (Loan loan : list) {
if (map.containsKey(loan.getRepayMethod())) {
map.get(loan.getRepayMethod()).add(loan);
} else {
List<Loan> groupList = new ArrayList<>();
groupList.add(loan);
map.put(loan.getRepayMethod(),groupList);
}
}
return map;
}
- 使用枚舉實(shí)現(xiàn)單例模式
public enum Singleton {
INSTANCE;
public void service() {
//todo
}
}
- 使用枚舉實(shí)現(xiàn)策略模式(適用于處理邏輯較為簡(jiǎn)單的策略模式)
public enum RepayTypeStrategy {
BULLET_REPAYMENT {
@Override
public void createLoanRepay(Loan loan) {
//todo
}
},
INTEREST {
@Override
public void createLoanRepay(Loan loan) {
//todo
}
};
public abstract void createLoanRepay(Loan loan);
}
相關(guān)原理
使用javap對(duì)編譯好的枚舉類字節(jié)碼進(jìn)行反編譯得到如下信息,可以發(fā)現(xiàn)其繼承自java.lang.Enum,其實(shí)現(xiàn)還是靜態(tài)常量的方式實(shí)現(xiàn)的,EnumSet和EnumMap利用到了Enum的ordinal字段,具體詳情可以查看源碼。
Compiled from "RepayMethod.java"
public final class com.yueyang.se.enumeration.RepayMethod extends java.lang.Enum<com.yueyang.se.enumeration.RepayMethod> {
public static final com.yueyang.se.enumeration.RepayMethod BULLET_REPAYMENT;
public static final com.yueyang.se.enumeration.RepayMethod INTEREST;
public static final com.yueyang.se.enumeration.RepayMethod EQUAL_INSTALLMENT;
public static final com.yueyang.se.enumeration.RepayMethod EQUAL_PRINCIPAL;
public static com.yueyang.se.enumeration.RepayMethod[] values();
public static com.yueyang.se.enumeration.RepayMethod valueOf(java.lang.String);
public java.lang.Integer getCode();
public void setCode(java.lang.Integer);
public java.lang.String getMsg();
public void setMsg(java.lang.String);
public static boolean isMultiplePeriod(com.yueyang.se.enumeration.RepayMethod);
static {};
}