简介
枚举类型是一种使用一组预定义的常量表示的一种特殊数据类型。enum关键字在 java5 中引入,所有的枚举类默认都集成自java.lang.Enum类。
//基本写法
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
枚举与常量比较
- 优点
- 可读性更高
- 编译时检查减少代码错误(相对于基本数据类型的常量)
- 表现力更强(相对于基本数据类型的常量)
- 使用 == 对枚举进行比较提供编译时和运行时的安全性
- 缺点
- 增加类的数目
- 数据转换麻烦
public class Date {
private Day day;
public static void main(String[] args) {
Date today = new Date();
//可能会出NPE
if (today.getDay().equals(Day.FRIDAY)) {
//todo
}
//使用==保证运行时安全
if (today.getDay() == Day.FRIDAY) {
//todo
}
//比较会得到true
if (today.getDay().equals(Color.FRIDAY)) {
//todo
}
//编译报错保证编译检查安全
//if (today.getDay() == Color.FRIDAY) {
//todo
//}
}
public Day getDay() {
return day;
}
public void setDay(Day day) {
this.day = day;
}
}
enum Color {
RED,GREEN,FRIDAY
}
使用场景与实例
- 在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 groupByRepayMethod(List list, RepayMethod repayMethod) {
return list.stream().filter(loan -> repayMethod == loan.repayMethod).collect(Collectors.toList());
}
}
- EnumSet
EnumSet 是一种专门为枚举类型所设计的 Set 类型。与HashSet相比,由于使用了内部位向量表示,因此它是特定 Enum 常量集的非常有效且紧凑的表示形式。EnumSet 是抽象类,其有两个实现:RegularEnumSet (小于等于64个元素使用)、JumboEnumSet,选择哪一个取决于实例化时枚举中常量的数量。使用EnumSet的of方法来构建EnumSet。
private static EnumSet 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是一个专门化的映射实现,用于将枚举常量用作键。与对应的 HashMap 相比,它是一个高效紧凑的实现,并且在内部表示为一个数组
public static EnumMap> groupByRepayMethod(List list) {
EnumMap> map = new EnumMap(RepayMethod.class);
for (Loan loan : list) {
if (map.containsKey(loan.getRepayMethod())) {
map.get(loan.getRepayMethod()).add(loan);
} else {
List groupList = new ArrayList<>();
groupList.add(loan);
map.put(loan.getRepayMethod(),groupList);
}
}
return map;
}
- 使用枚举实现单例模式
public enum Singleton {
INSTANCE;
public void service() {
//todo
}
}
- 使用枚举实现策略模式(适用于处理逻辑较为简单的策略模式)
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);
}
相关原理
使用javap对编译好的枚举类字节码进行反编译得到如下信息,可以发现其继承自java.lang.Enum,其实现还是静态常量的方式实现的,EnumSet和EnumMap利用到了Enum的ordinal字段,具体详情可以查看源码。
Compiled from "RepayMethod.java"
public final class com.yueyang.se.enumeration.RepayMethod extends java.lang.Enum {
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 {};
}