JAVA 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。并且做到了对调用者的隔离。

是不是感觉枚举被玩出花了呢。写代码还真是博大精深的事情!!

猜你喜欢

转载自blog.csdn.net/weixin_40292704/article/details/107778681