enum 的几种用法介绍
好久不写博客了,必须鞭策自己一下。还是要坚持✊,写博客是值得做的有意义的事。
枚举类型enum是从jdk1.5后新增的类型,已经是大家经常使用的类型,主要用来代替各种常量。而把enum用好绝对可以简化我们的代码,使代码更加整洁。
下面整理了几种用法供大家参考。
1,将lambda表达式写到enum中
这一点主要是随着java8以后,函数式编程的兴起,很多繁琐的代码可以用表达式来代替,那么将表达式写到enum中也是自然而然的了。
public enum TendencyTypeEnum {
/**
* 全部
*/
ALL(0, "COIN_TENDENCY_ALL", () -> 0L),
/**
* 1天
*/
ONE_DAY(1, "COIN_TENDENCY_ONE_DAY", () -> DateUtil.getPastDate(1)),
/**
* 7天
*/
SVEN_DAY(2, "COIN_TENDENCY_SEVEN_DAY", () -> DateUtil.getPastDate(7)),
/**
* 1个月
*/
ONE_MONTH(3, "COIN_TENDENCY_ONE_MONTH", () -> DateUtil.getPastMonth(1)),
/**
* 三个月
*/
THREE_MONTH(4, "COIN_TENDENCY_THREE_MONTH", () -> DateUtil.getPastMonth(3)),
/**
* 一年
*/
ONE_YEAR(5, "COIN_TENDENCY_ONE_YEAR", () -> DateUtil.getPastMonth(12)),
/**
* 六个月
*/
SIX_MONTH(6, "COIN_TENDENCY_SIX_MONTH", () -> DateUtil.getPastMonth(6)),
/**
* 今年以来
*/
THIS_YEAR(7, "COIN_TENDENCY_THIS_YEAR", DateUtil::getYearStartTime);
/**
* 枚举值
*/
private int value;
/**
* 缓存队列key
*/
private String cacheKeyFix;
/**
* 生成对应的vo中的开始时间 0点
*/
private TendencyTypeEnum.TimeTemplate oldestZeroTimeTemplate;
TendencyTypeEnum(int value, String cacheKeyFix, TendencyTypeEnum.TimeTemplate oldestZeroTimeTemplate) {
this.value = value;
this.cacheKeyFix = cacheKeyFix;
this.oldestZeroTimeTemplate = oldestZeroTimeTemplate;
}
/**
* 自定义的函数式接口
*/
interface TimeTemplate {
long get();
}
public int getValue() {
return value;
}
public String getCacheKeyFix() {
return cacheKeyFix;
}
public long provideOldestZeroTime() {
return oldestZeroTimeTemplate.get();
}
}
如上例,定义了各种时间类型的枚举,1天,7天,1月,3月等。oldestZeroTimeTemplate参数用来标记这些时间的开始时间戳。provideOldestZeroTime方法返回了这些时间的开始时间,我们可以通过这个方法直接返回需要的开始时间。当然,如果你需要用的地方本身就需要一个表达式,那就更方便了。
要注意一点oldestZeroTimeTemplate只能是一个表达式类型,而不应该直接用Dateutil.getPastDate(1)方法等,因为我们知道枚举类型实际上是程序帮我们提前new好了这些对象,如果直接用Dateutil.getPastDate(1)那么这个属性的值就直接写死了,不会被改变,而我们期望的是在程序调用的时候拿到PastDate(1)的值,所以必须用表达式写成()->Dateutil.getPastDate(1)
2,枚举和行为绑定
定义一个加减乘除的枚举
public class ActiveEnum {
public enum NormalActive{
PLUS,MINUS,MULTI,DIVIDS,DIFFER;
double oper(double x,double y) {
switch(this) {
case PLUS:return x+y;
case MINUS:return x-y;
case MULTI:return x*y;
case DIVIDS:return x/y;
}
throw new UnsupportedOperationException();
}
}
}
这个枚举乍看之下没什么问题,但不是一个完美的代码。
首先我们需要throw new UnsupportedOperationException();来处理额外的情况。可以看到有一只计算形式一种微分DIFFER,他没有相应的计算方式,编译器不会提示任何的错误,只有在调用的时候才会抛出UnsupportedOperationException。
我们希望这种错误在便携调试代码的时候越早发现越好,有没有什么写法可以避免到这个问题呢?
public enum BetterActive{
PLUS {
@Override
double oper(double x, double y) {
return x+y;
}
},MINUS {
@Override
double oper(double x, double y) {
return x-y;
}
};
abstract double oper(double x,double y);
}
BetterActive方法中新增了抽象方法oper,使得定义的每个枚举必须实现方法才能编译通过,达到了绑定行为的目的。
这里重复一下枚举的实现,枚举本质上就是一个类,枚举中的每个枚举类型就是它的一个实例。
3,策略型枚举
定义一个计算加班工资的枚举
/**
* 类说明:加班费计算,工作日加班2倍,节假日3倍
*/
enum PayDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY, WUYI;
private static final int HOURS_WORK = 2;
private static final int HOURS_REST = 3;
//超时时间
double pay(double hoursOvertime) {
switch (this) {
case SATURDAY:
case SUNDAY:
return hoursOvertime * HOURS_REST;
default:
return hoursOvertime * HOURS_WORK;
}
}
}
依然是这样的问题,定义了WUYI,本来应该按照3被工资算的,结果走到了default中,按2被工资算了。
这时如果依然定义一个行为方法,也可以解决问题,但是很糟糕的是需要在每个枚举后面去写hoursOvertime * HOURS_WORK这样的方法,依然造成了不可必要的代码冗余。
我们需要一个策略枚举:
public enum BetterPayDay {
MONDAY(PayType.WORK), TUESDAY(PayType.WORK), WEDNESDAY(
PayType.WORK), THURSDAY(PayType.WORK), FRIDAY(PayType.WORK),
SATURDAY(PayType.REST), SUNDAY(PayType.REST), WUYI(PayType.REST);
private final PayType payType;//成员变量
BetterPayDay(PayType payType) {
this.payType = payType;
}
double pay(double hoursOvertime) {
return payType.pay(hoursOvertime);
}
//策略枚举
private enum PayType {
WORK {
@Override
double pay(double hoursOvertime) {
return hoursOvertime * HOURS_WORK;
}
},
REST {
@Override
double pay(double hoursOvertime) {
return hoursOvertime * HOURS_REST;
}
};
private static final int HOURS_WORK = 2;
private static final int HOURS_REST = 3;
abstract double pay(double hoursOvertime);//抽象计算加班费的方法
}
public static void main(String[] args) {
System.out.println(BetterPayDay.MONDAY.pay(7.5));
}
}
策略枚举PayType中定义了WORK,REST两种类型,并定义了抽象计算加班费的方法,两种类型来实现它。
这样BetterPayDay中只需要定义PayType属性,这样在定义每一个BetterPayDay的类型时需要指定PayType。并且做到了对调用者的隔离。
是不是感觉枚举被玩出花了呢。写代码还真是博大精深的事情!!