Android基礎(chǔ)進(jìn)階之EffectiveJava翻譯系列(第五章:枚舉和注解)

Java1.5中提供的兩種新類型

Item30: 用枚舉替代int型常量

枚舉:一系列常量類型的集合
沒有枚舉前大量定義的常量如下

    // The int enum pattern - severely deficient!
    public static final int APPLE_FUJI = 0;
    public static final int APPLE_PIPPIN = 1;
    public static final int APPLE_GRANNY_SMITH = 2;
    public static final int ORANGE_NAVEL = 0;
    public static final int ORANGE_TEMPLE = 1;
    public static final int ORANGE_BLOOD = 2;

首先調(diào)試不方便,我們只會(huì)打印出數(shù)字,然后回歸代碼
其次沒有命名空間做區(qū)別,命名累贅
使用枚舉后

    public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
    public enum Orange { NAVEL, TEMPLE, BLOOD }

再來看一個(gè)星球的例子

public enum Planet {
    MERCURY(3.302e+23, 2.439e6),
    VENUS (4.869e+24, 6.052e6),
    EARTH (5.975e+24, 6.378e6),
    MARS (6.419e+23, 3.393e6),
    JUPITER(1.899e+27, 7.149e7),
    SATURN (5.685e+26, 6.027e7),
    URANUS (8.683e+25, 2.556e7),
    NEPTUNE(1.024e+26, 2.477e7);
    private final double mass; // In kilograms
    private final double radius; // In meters
    private final double surfaceGravity; // 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
    }
}

再來看一個(gè)算數(shù)的例子

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);
}

總結(jié):枚舉比int型常量更安全和具有可讀性

Item31: Use instance fields instead of ordinals(使用實(shí)例字段代替序號(hào))

所有的枚舉都有
ordinal 方法(從0開始計(jì)數(shù)),如果我們想用序號(hào)的int值(從1開始計(jì)數(shù)),不要直接修改ordinal 方法

//bad
public enum Ensemble {
    SOLO, DUET, TRIO, QUARTET, QUINTET,
    SEXTET, SEPTET, OCTET, NONET, DECTET;
    public int numberOfMusicians() { return ordinal() + 1; }
}

雖然上述代碼能正常使用,但是卻會(huì)導(dǎo)致一場噩夢
如果我們改變了枚舉中的常量順序,之前的序號(hào)就會(huì)一團(tuán)糟
優(yōu)化代碼如下

public enum Ensemble {
    SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
    SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
    NONET(9), DECTET(10), TRIPLE_QUARTET(12);
    
    private final int numberOfMusicians;
    
    Ensemble(int size) { 
        this.numberOfMusicians = size; 
    }
    
    public int numberOfMusicians() { 
        return numberOfMusicians; 
    }
}
Item32: Use EnumSet instead of bit fields(用EnumSet替代位字段)

如我們有一段代碼

// Bit field enumeration constants - OBSOLETE!
public class Text {
  public static final int STYLE_BOLD = 1 << 0; // 1
  public static final int STYLE_ITALIC = 1 << 1; // 2
  public static final int STYLE_UNDERLINE = 1 << 2; // 4
  public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8
  // Parameter is bitwise OR of zero or more STYLE_ constants
  public void applyStyles(int styles) { ... }
}
  //使用
  text.applyStyles(STYLE_BOLD | STYLE_ITALIC);

用EnumSet優(yōu)化如下:

// 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));
Item33: Use EnumMap instead of ordinal indexing(使用EnumMap代替順序索引)

EnumSet/EnumMap詳解

Item34: 使用接口提升枚舉的擴(kuò)展性

code say everything
普通操作 加減乘除

// Emulated extensible enum using an interface
public interface Operation {
    double apply(double x, double y);
}
public enum BasicOperation implements 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;
    BasicOperation(String symbol) {
        this.symbol = symbol;
    }
    @Override public String toString() {
        return symbol;
    }
}

現(xiàn)需要擴(kuò)展取余,異或等方法,不要再BasicOperation 中新加枚舉,而是實(shí)現(xiàn)公共接口Operation

// Emulated extension enum
public enum ExtendedOperation implements Operation {
    EXP("^") {
        public double apply(double x, double y) {
            return Math.pow(x, y);
        }
    },
    REMAINDER("%") {
        public double apply(double x, double y) {
            return x % y;
        }
    };
 
    private final String symbol;
    ExtendedOperation(String symbol) {
        this.symbol = symbol;
    }
    @Override public String toString() {
        return symbol;
    }
}
Item36: 始終使用override注解
// 你能找到這個(gè)bug嗎?
public class Bigram {
    private final char first;
    private final char second;
    public Bigram(char first, char second) {
        this.first = first;
        this.second = second;
    }
    public boolean equals(Bigram b) {
        return b.first == first && b.second == second;
    }
    public int hashCode() {
        return 31 * first + second;
    }
    
    public static void main(String[] args) {
        Set<Bigram> s = new HashSet<Bigram>();
        for (int i = 0; i < 10; i++)
            for (char ch = 'a'; ch <= 'z'; ch++)
              s.add(new Bigram(ch, ch));
        System.out.println(s.size());
    }
}

理論上我們希望打印26,因?yàn)镠ashSet沒有重復(fù)元素,但是得到的值是260
因?yàn)闆]有override equals&hashCode方法,所以默認(rèn)是使用的"=="比較的地址,得到的都是不同的對象
修復(fù)如下

    @Override public boolean equals(Bigram b) {
        return b.first == first && b.second == second;
    }
    @Override public int hashCode() {
        return 31 * first + second;
    }
Item37: 使用標(biāo)記接口定義類型(待補(bǔ)充)
  • 標(biāo)記接口:只為了標(biāo)記某一種類型
    如 Serializable 接口,表明可將實(shí)例序列化
    優(yōu)點(diǎn):
    1.標(biāo)記接口定義了一種類型
    2.可用于任何擴(kuò)展的子類

  • 標(biāo)記注解:
    優(yōu)點(diǎn):
    1.描述信息更豐富,可在使用后添加方法
    2.位于FrameWork層,各個(gè)應(yīng)用使用同一套規(guī)則


上一章:泛型
下一章:方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末计济,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌乍构,老刑警劉巖由蘑,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件只估,死亡現(xiàn)場離奇詭異霸株,居然都是意外死亡诸衔,警方通過查閱死者的電腦和手機(jī)盯漂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笨农,“玉大人就缆,你說我怎么就攤上這事≮艘啵” “怎么了竭宰?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長份招。 經(jīng)常有香客問我切揭,道長,這世上最難降的妖魔是什么脾还? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任伴箩,我火速辦了婚禮,結(jié)果婚禮上鄙漏,老公的妹妹穿的比我還像新娘。我一直安慰自己棺蛛,他們只是感情好怔蚌,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著旁赊,像睡著了一般桦踊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上终畅,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天籍胯,我揣著相機(jī)與錄音竟闪,去河邊找鬼。 笑死杖狼,一個(gè)胖子當(dāng)著我的面吹牛炼蛤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播蝶涩,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼理朋,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了绿聘?” 一聲冷哼從身側(cè)響起嗽上,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熄攘,沒想到半個(gè)月后兽愤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挪圾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年烹看,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洛史。...
    茶點(diǎn)故事閱讀 40,675評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惯殊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出也殖,到底是詐尸還是另有隱情土思,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布忆嗜,位于F島的核電站己儒,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捆毫。R本人自食惡果不足惜闪湾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望绩卤。 院中可真熱鬧途样,春花似錦、人聲如沸濒憋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽凛驮。三九已至裆站,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宏胯。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工羽嫡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人肩袍。 一個(gè)月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓杭棵,卻偏偏與公主長得像,于是被迫代替她去往敵國和親了牛。 傳聞我的和親對象是個(gè)殘疾皇子颜屠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內(nèi)容