优雅编程之这样使用枚举和注解,你就“正常”了(二十九)

开心一笑

视频教程

大家好,我录制的视频《Java之优雅编程之道》已经在CSDN学院发布了,有兴趣的同学可以购买观看,相信大家一定会收获到很多知识的。谢谢大家的支持……

视频地址:http://edu.csdn.net/lecturer/994

提出问题

项目中如何使用枚举和注解???

解决问题

用enum替换int常量

例如:下面是公司项目的一个标准的enum实例。

package com.evada.de.common.enums;

/**
 * 状态枚举
 * @author Ay
 */
public enum StatusEnum {
    /** 0:已删除 */
    DELETED("0","已删除"),
    /** 1:启用 */
    ENABLE("1","启用"),
    /** 2:禁用 */
    DISABLE("2","禁用");

    /** 状态值 */
    private final String code;

    private final String name;

    private StatusEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }

    @Override
    public String toString() {
        return code;
    }

    public String getName() {
        return name;
    }
}

注意,与枚举常量关联的行为,最好被实现成私有的或者包级私有的方法。

例如:

package com.evada.de;

/**
 * Created by Ay on 2016/10/2.
 */
public enum Operation {

    PLUS,MINUS,TIMES,DIVIDE;

    double apply(double x,double y){
        switch (this){
            case PLUS:return x + y;
            case MINUS:return x - y;
            case TIMES:return x * y;
            case DIVIDE:return x / y;
        }
        throw new AssertionError("Unknow op: " + this);
    }
}

上面代码是很脆弱的,如果添加一种类型,却忘记给switch添加相应的条件,枚举仍然可以编译,但是当你试图运用新的运算时,就会运行失败。

修改过后的实例:

package com.evada.de;

/**
 * Created by Ay on 2016/10/2.
 */
public enum Operation {

    PLUS("+"){
        @Override
        double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-"){
        @Override
        double apply(double x, double y) {
            return x - y;
        }
    },
    TIMES("*"){
        @Override
        double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/"){
        @Override
        double apply(double x, double y) {
            return x / y;
        }
    };

    private final String symbol;
    Operation(String symbol){this.symbol = symbol;}

    @Override
    public String toString() { return this.symbol;}
    abstract double apply(double x,double y);
}

下面看一个嵌套枚举实例:个人感觉这段代码很优雅,贴出来相互学习下:

如果多个枚举常量同时共享相同的行为,则考虑策略枚举(嵌套枚举)。

/**
 * Created by Ay on 2016/10/2.
 */
public enum PayrollDay {

    MonDAY(PayType.WEEKDAY),
    WEEKDAY(PayType.WEEKDAY),
    TUESDAY(PayType.WEEKDAY),
    WENDESDAY(PayType.WEEKDAY),
    THURSDAY(PayType.WEEKDAY),
    FRIDAY(PayType.WEEKDAY),
    SATURDAY(PayType.WEEKEND),
    SUNDAY(PayType.WEEKEND);

    private PayType payType;

    PayrollDay(PayType payType){ this.payType = payType;}

    double pay(double hoursWorked,double payRate){
        return payType.pay(hoursWorked,payRate);
    }
    //这里是嵌套枚举
    private enum PayType{

        WEEKDAY{
            @Override
            double overtimePay(double hrs, double payRate) {
                return 0;
            }
        },WEEKEND{
            @Override
            double overtimePay(double hrs, double payRate) {
                return 0;
            }
        };

        private static final int HOURS_PRE_SHIFT = 8;

        abstract double overtimePay(double hrs,double payRate);

        double pay(double hoursWorked,double payRate){
            double basePay = hoursWorked * payRate;
            return basePay + overtimePay(hoursWorked,payRate);
        }
    }
}

枚举有个小小的性能缺点,即装载和初始化枚举时会有空间和时间成本。

总而言之,与int常量相比,枚举类型的优势是不可言喻的。枚举要易读得多,也更加安全,功能更加强大。

用实例域替换序数

例如:

enum Ensemble{
    SOLO,DUET,TRIO,QUARTET,QUINTET,SEXTET,SEPTEX,OCTEX,NONET,DECTET;
    public int numberOfMusicians(){
        return ordinal() + 1;//ordinal()用来返回枚举常量在类型中的数字位置。
    }
}

永远不要根据枚举的序数导出与它关联的值,而是要将它保存在一个实例域中:

正确做法是:

enum Ensemble{
    SOLO(1),DUET(2),TRIO(3),QUARTET(4),QUINTET(5),
    SEXTET(6),SEPTEX(7),OCTEX(8),NONET(9),DECTET(10);

    private final int numberOfMusicians;

    Ensemble(int size){
        this.numberOfMusicians = size;
    }

    public int numberOfMusicians(){
        return ordinal() + 1;
    }

}

Enum规范中写道:大多数程序员都不需要这个方法。除非你在编写的是这种数据结构,否则最好避免使用original方法。

用EnumSet代替位域

用OR位运算,将几个常量合并到一个集合中,称为位域。

class Text{
    public static final int STYLE_BOLE = 1 << 0;
    public static final int STYLE_ITALIC = 1 <<1;
    public static final int STYLE_UNDERLINE = 1 <<2;
    public static final int STYLE_STRIKETHROUGH = 1 <<3;
    public void applyStyles(int styles){ ... }
}

将前一个范例改为用枚举代替位域后的代码为:

class Text{

    public enum Style{BOLE,ITALIC,UNDERLINE,STRIKETHROUGH}
    public void applyStyles(Set