1. 程式人生 > >Effective Java讀書筆記(五)

Effective Java讀書筆記(五)

用enum代替int常量

// Enum type with data and behavior
public enum Planet {
    MERCURY (3.302e+23, 2.439e6),
    VENUS   (4.869e+24, 6.052e6),
    MARS    (5.975e+24, 6.37e86),

    ...

    NEPTUNE (1.024e=26, 2.477e7);

    private final double mass;              // in kilograms
    private final double radius;            // in meters
private final double serfaceGravity; // in m / s^2 // Universal gravitational constant in m^3 /kg s^2 private static final double G = 6.67300e-11; // Constructor 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 surfaceGravity() { return surfaceGravity; } public double surfaceWeight(double mass) { return mass * surfaceGravity; // F = ma; } }

將不同的行為與每個常量關聯。

// Enum type with constant-specific method implementations
public enum Operation { PLUS { double apply(double x, double y){ return x + y; } }, MINUS { double apply(double x, double y){ return x - y; } }, TIMES { double apply(double x, double y){ return x * y; } }, DIVIDE { double apply(double x, double y){ return x / y; } }; abstract double apply(double x, double y); }

策略列舉。

// The strategy enum pattern
enum PayrollDay {
    MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY),
    WEDNESDAY(PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY),
    FRIDAY(PayType.WEEKDAY),
    SATURDAY(PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

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

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

    // The strategy enum type
    private enum PayType {
        WEEKDAY {
            double overtimePay(double hours, double payRate) {
                return hours <= HOURS_PER_SHIFT ? 0 :
                    (hours - HOURS_PER_SHIFT) * payRate / 2;
            }
        },

        WEEKEND {
            double overtimePay(double hours, double payRate) {
                return hours * payRate / 2;
            }
        };

        private static final int HOURS_PER_SHIFT = 8;

        abstract double overtimePay(double hrs, double payRate);

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

用例項域代替序數

不要根據列舉的序數匯出與它關聯的值,而是要將它儲存在一個例項域中。

“大多數程式設計師都不需要這個方法(oridinal)。它是設計成用於像E怒罵Set和E怒罵Map這種基於列舉的通用資料結構的。”

用EnumSet代替位域

// Bit field enumeration constants
public class Text {
    public static final int STYLE_BOLD          = 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;

    // Parameter is bitwise OR of zero or mote STYLE
    public void applyStyles(int stype) { ... }
}

text.applyStyles(STYLE_BOLD | STYPE_ITALIC);

// EnumSet a modern replacement for bit fields
public class Text {
    public enum Style { BOLD, ITALIC, UNDERLINE, STRIKETHROUGH }

    // Any set could be passed in, but EnumSet is clearly best
    public void applyStyles(Set<Style> styles) { ... }
}

text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));

用EnumMap代替序數索引

下面的類用來表示一種烹飪用的香草:

public class Herb {
    public enum Type { ANNUAL, PERENNIAL, BIENNIAL }

    private final String name;
    private final Type type;

    Herb(String name, Type type) {
        this.name = name;
        this.type = type;
    }

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

現在假設有一個香草的陣列,表示一座花園中的職務, 要按照型別(一年生、多年生或者兩年生植物)進行組織之後將這些植物列出來。

// Using oridinal() to index an array - DON'T DO THIS!
Herb[] garden = ...;

Set<Herb>[] herbsByType = (Set<Herb[]>)new Set[Herb.Type.values().length];
for(int i = 0; i < herbsByType.length; i++)
    herbsByType[i] = new HashSet<Herb>();

for(Herb h : garden) 
    herbsByType[h.types.oridinal()].add(h);

// Print the result
for(int i = 0; i < herbsByType.length; i++){
    System.out.printf( ... );
}

// Using and EnumMap to associate data with an enum
Map<Herb.Type, Set<Herb>> herbsByType = 
    new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);

for(Herb.Type t : Herb.Type.values())
    herbsByType.put(t, new HashSet<Herb>());

for(Herb h : garden){
    herbsByType.get(h.type).add(h);

System.out.println(herbsByType);
}