Effective Java讀書筆記(五)
阿新 • • 發佈:2019-02-02
用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);
}