java 枚举类型使用总结

注:阅读了effective java 讲诉enum的部分,做下笔记,下文中大部分代码来自effective java书中

枚举类型是指由一组固定的常量组成的合法值得类型。

使用枚举的好处:a,因为没有可以访问的构造器,枚举类型是真正的final;

        b,枚举类型提供类编译时的类型安全。如:函数中声明一个参数类型为枚举类型的Apple时,那么调用方法时传递到参数上的任何非null对象一定是Apple的值之一,         而是用静态常量就无法保证;

        c,包含同名常量的多个枚举类型可以和平共处,每个类型都有自己的命名空间

        d,枚举类型允许添加任意的方法和域,并可实现接口。

1,常见的一组简单的枚举

如:

public enum Apple {
    FUJI,PIPPIN,CRANNY_SMITH
}

2,带有具体值的枚举(可自定义方法)

public enum Apple {
    FUJI(1), PIPPIN(2), CRANNY_SMITH(3);
    
    private final int code;
    
    Apple(int code) {
        this.code = code;
    }

    public int getCode() {
        return code;
    }

    public static Apple fromCode(int code) {
        for (Apple apple : Apple.values()) {
            if (apple.getCode() == code)
                return apple;
        }
        return null;
    }
}

3,多个参数,并带有运算方法

public enum Planet {

    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6),
    MARS(6.421e+23, 3.3972e6),
    JUPITER(1.9e+27, 7.1492e7),
    SATURN(5.688e+26, 6.0268e7),
    URANUS(8.686e+25, 2.5559e7),
    NEPTUNE(1.024e+26, 2.4746e7),
    PLUTO(1.27e+22, 1.137e6);
    
    private final double mass;

    private final double radius;

    private final double surfaceGravity;// m/ s^2

    public static final double G = 6.67300E-11;

    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
        surfaceGravity = G * mass / (radius * radius);
    }

    public double mass() {
        return mass;
    }

    public double radius() {
        return radius;
    }

    public double surfaceWeight(double otherMass) {
        return otherMass * surfaceGravity;
    }
}

4,根据不同的常量有不同的方法

  switch方法 ----不推荐(有可能新添加了常量却没有在switch中加入就悲剧了)

public enum Operation {
    PLUS("+"),
    MINUS("-"),
    TIMES("*"),
    DIVIDE("/");
    
    private final String symbol;
    Operation(String symbol){
        this.symbol=symbol;
    }
    
    public String getSymbol() {
        return symbol;
    }

    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("unknown operation: "+this);
    }

  推荐:constant-specific method implementation

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

    private final String symbol;

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

    public String getSymbol() {
        return symbol;
    }

    public abstract double apply(double x, double y);

}

5,策略枚举 strategy enum

先来看一种情况:通过一周的工作时间来计算工资,工作时间8小时,额外算加班,周末工作也算加班

首先我们可以使用switch来做,这样看起来十分简单

public enum PayrollDay {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FIRDAY, SATURDAY, SUNDAY;

    private static final int HOURS_PER_SHIFT = 8;

    double pay(double hoursWorked, double payRate) {
        double basePay = hoursWorked * payRate;
        double overtimePay;
        switch (this) {
        case SATURDAY:
        case SUNDAY:
            overtimePay = hoursWorked * payRate * 2;
        default:
            overtimePay = hoursWorked <= HOURS_PER_SHIFT ? 0
                    : (hoursWorked - HOURS_PER_SHIFT) * payRate * 2;
            break;
        }
        return basePay + overtimePay;
    }
}

但是同样有可能出现上面提到不严谨的问题,当枚举常量增加时,switch可能忘记加入

使用策略枚举时 如下:

public enum PayrollDay {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
            PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FIRDAY(PayType.WEEKDAY), SATURDAY(
            PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

    private final PayType payType;

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

    public PayType getPayType() {
        return payType;
    }

    double pay(double hoursWorked, double payRate) {
        return payType.pay(hoursWorked, payRate);
    }

    enum PayType {
        WEEKDAY {
            @Override
            double overtimePay(double hours, double payRate) {
                return hours < HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
                        * payRate * 2;
            }
        },
        WEEKEND {
            @Override
            double overtimePay(double hours, double payRate) {
                return hours * payRate * 2;
            }
        };
        private static final int HOURS_PER_SHIFT = 8;

        abstract double overtimePay(double hours, double payRate);

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

6,上面几个例子中都不推荐时间switch,那么什么时候使用呢

枚举中的switch语句适用于给外部的枚举类型增加特定于常量的行为。如:上面例子中的operation 如果希望他有一个方法返回对应的逆运算

public static Operation inverse(Operation op) {
        switch (op) {
        case PLUS:
            return Operation.MINUS;
        case MINUS:
            return Operation.PLUS;
        case TIMES:
            return Operation.DIVIDE;
        case DIVIDE:
            return Operation.TIMES;
        default:
            throw new AssertionError("unknown operation : " + op);
        }
    }

 

posted @ 2014-11-01 18:04  china2k  阅读(433)  评论(0编辑  收藏  举报