優(yōu)雅編程之這樣使用枚舉和注解克懊,你就“正吵栏ǎ”了(二十九)

開心一笑

提出問題

項(xiàng)目中如何使用枚舉和注解???

解決問題

用enum替換int常量

例如:下面是公司項(xiàng)目的一個(gè)標(biāo)準(zhǔn)的enum實(shí)例。

package com.evada.de.common.enums;

/**
 * 狀態(tài)枚舉
 * @author Ay
 */
public enum StatusEnum {
    /** 0:已刪除 */
    DELETED("0","已刪除"),
    /** 1:啟用 */
    ENABLE("1","啟用"),
    /** 2:禁用 */
    DISABLE("2","禁用");

    /** 狀態(tài)值 */
    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;
    }
}

注意谭溉,與枚舉常量關(guān)聯(lián)的行為墙懂,最好被實(shí)現(xiàn)成私有的或者包級(jí)私有的方法。

例如:

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添加相應(yīng)的條件,枚舉仍然可以編譯扔亥,但是當(dāng)你試圖運(yùn)用新的運(yùn)算時(shí),就會(huì)運(yùn)行失敗谈为。

修改過后的實(shí)例:

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

下面看一個(gè)嵌套枚舉實(shí)例:個(gè)人感覺這段代碼很優(yōu)雅旅挤,貼出來相互學(xué)習(xí)下:

如果多個(gè)枚舉常量同時(shí)共享相同的行為,則考慮策略枚舉(嵌套枚舉)伞鲫。

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

枚舉有個(gè)小小的性能缺點(diǎn)粘茄,即裝載和初始化枚舉時(shí)會(huì)有空間和時(shí)間成本。

總而言之,與int常量相比柒瓣,枚舉類型的優(yōu)勢(shì)是不可言喻的儒搭。枚舉要易讀得多,也更加安全芙贫,功能更加強(qiáng)大搂鲫。

用實(shí)例域替換序數(shù)

例如:

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

永遠(yuǎn)不要根據(jù)枚舉的序數(shù)導(dǎo)出與它關(guān)聯(lián)的值磺平,而是要將它保存在一個(gè)實(shí)例域中:

正確做法是:

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規(guī)范中寫道:大多數(shù)程序員都不需要這個(gè)方法魂仍。除非你在編寫的是這種數(shù)據(jù)結(jié)構(gòu),否則最好避免使用original方法拣挪。

用EnumSet代替位域

用OR位運(yùn)算擦酌,將幾個(gè)常量合并到一個(gè)集合中,稱為位域菠劝。

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){ ... }
}

將前一個(gè)范例改為用枚舉代替位域后的代碼為:

class Text{

    public enum Style{BOLE,ITALIC,UNDERLINE,STRIKETHROUGH}
    public void applyStyles(Set<Style> styles){}
}

總而言之赊舶,正是因?yàn)槊杜e類型要用在集合中,所以沒有理由用位域來表示它赶诊。

用EnumMap代替序數(shù)索引

說白了笼平,就是類似于key和value形式,具體可以看《Effective Java》的具體實(shí)例甫何。

總而言之出吹,最好不要用序數(shù)來索引數(shù)組,而要使用EnumMap辙喂。如果你所表示的這種關(guān)系是多維的捶牢,就使用EnumMap<...,EnumMap<...>>。運(yùn)用程序的程序員在一般情況下都不使用Enum.oridinal,即使要用也很少巍耗,因此這是一種特殊情況秋麸。

用接口模擬可伸縮的枚舉

例如:

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 symbool;
    BasicOperation(String symbool){ this.symbool = symbool}

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

    @Override
    public double apply(double x, double y) {
        return 0;
    }
}

上面例子有很好的擴(kuò)展性,假設(shè)你想要定義一個(gè)上述操作類型的擴(kuò)展炬太,由求冪和求余操作組成灸蟆,你需要做的就是編寫一個(gè)枚舉類型,讓它實(shí)現(xiàn)Operation接口:

public interface Operation{
    double apply(double x,double y);
}

public enum BasicOperation implements Operation{

    PLUS("^"){
        public double apply(double x,double y){ return Math.pow(x,y);}
    },
    MINUS("%"){
        public double apply(double x,double y){ return x % y;}
    };

    private final String symbool;
    BasicOperation(String symbool){ this.symbool = symbool}

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

    @Override
    public double apply(double x, double y) {
        return 0;
    }
}

總而言之亲族,雖然無法編寫可擴(kuò)展的枚舉類型炒考,卻可以通過編寫接口以及實(shí)現(xiàn)該接口的基礎(chǔ)枚舉類型,對(duì)它進(jìn)行模擬霎迫。這樣允許客戶端編寫自己的枚舉來實(shí)現(xiàn)接口斋枢。如果API是根據(jù)接口編寫的,那么在可以使用基礎(chǔ)枚舉類型的任何地方知给,也都可以使用這些枚舉瓤帚。

注解優(yōu)先于命名模式

命名模式:表明有些程序元素需要通過某種工具或者框架進(jìn)行特殊處理描姚。例如,Junit測(cè)試框架原本要求它的用戶一定要用test作為測(cè)試方法名稱的開頭戈次。

例如:

@Test
public void testLove(){
    System.out.println("I love you!!!");
}

總而言之,使用注解而不是命名模式

堅(jiān)持使用Override注解

@Override只能用在方法聲明中轩勘,它表示被注解的方法聲明覆蓋了超類型中的一個(gè)聲明。如果堅(jiān)持使用這個(gè)注解怯邪,可以防止一大類的非法錯(cuò)誤绊寻。

在你想要覆蓋超類聲明的每個(gè)方法聲明中使用Override注解。

總而言之擎颖,如果在你想要的每個(gè)方法聲明中使用Override注解來覆蓋超類聲明榛斯,編譯器就可以防止大量的錯(cuò)誤,但有一個(gè)例外搂捧。在具體的類中驮俗,不必標(biāo)注你確信覆蓋了抽象方法聲明的方法。

用標(biāo)記接口定義類型

標(biāo)記接口:是沒有包含方法聲明的接口允跑,而只是指明一個(gè)類實(shí)現(xiàn)了具有某種屬性的接口王凑。例如:Serializable.

標(biāo)記接口勝過標(biāo)記注解:標(biāo)記接口定義的類型是由被標(biāo)記類的實(shí)例實(shí)現(xiàn)的;標(biāo)記注解則沒有定義這樣的類型聋丝。

標(biāo)記注解勝過標(biāo)記接口:它可以通過默認(rèn)的方式添加一個(gè)或者多個(gè)注解類型的元素索烹,給已被使用的注解類型添加更多的信息。

那么該如何選擇弱睦?

如果標(biāo)記是運(yùn)用到任何程序元素而不是類或者接口百姓,就必須使用注解,因?yàn)橹挥蓄惡徒涌诳梢杂脕韺?shí)現(xiàn)或者擴(kuò)展接口况木。如果標(biāo)記只運(yùn)用給類和接口垒拢,就要問問自己:我要編寫一個(gè)還是多個(gè)只接受有這種標(biāo)記的方法?如果是這種情況火惊,就應(yīng)該優(yōu)先使用標(biāo)記接口而非注解求类。這樣你就可以用接口作為相關(guān)方法的參數(shù)類型,它真正可以為你提供編譯時(shí)進(jìn)行類型檢查的好處屹耐。

讀書感悟

來自亦舒《流金歲月》

  • 無論做什么尸疆,記得為自己而做,那就毫無怨言惶岭。
  • 那種難得的朋友寿弱。我成功,她不嫉妒按灶。我委靡脖捻,她不輕視。人生得一知己足矣兆衅。
  • 快樂是要去尋找的,很少有天生幸福的人。
  • 你看得起你自己就好羡亩,管誰看不起你摩疑,肯幫固然好,不幫拉倒畏铆。
  • 氣質(zhì)雷袋,讀書的唯一的用途是增加氣質(zhì)。世上確有氣質(zhì)這回事辞居。

其他

如果有帶給你一絲絲小快樂楷怒,就讓快樂繼續(xù)傳遞下去,歡迎轉(zhuǎn)載瓦灶,點(diǎn)贊鸠删,頂,歡迎留下寶貴的意見贼陶,多謝支持刃泡!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碉怔,隨后出現(xiàn)的幾起案子烘贴,更是在濱河造成了極大的恐慌,老刑警劉巖撮胧,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桨踪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡芹啥,警方通過查閱死者的電腦和手機(jī)锻离,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來叁征,“玉大人纳账,你說我怎么就攤上這事∞嗵郏” “怎么了疏虫?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長啤呼。 經(jīng)常有香客問我卧秘,道長,這世上最難降的妖魔是什么官扣? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任翅敌,我火速辦了婚禮,結(jié)果婚禮上惕蹄,老公的妹妹穿的比我還像新娘蚯涮。我一直安慰自己治专,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布遭顶。 她就那樣靜靜地躺著张峰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棒旗。 梳的紋絲不亂的頭發(fā)上喘批,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音铣揉,去河邊找鬼饶深。 笑死,一個(gè)胖子當(dāng)著我的面吹牛逛拱,可吹牛的內(nèi)容都是我干的敌厘。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼橘券,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼额湘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起旁舰,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤锋华,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后箭窜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體毯焕,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年磺樱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纳猫。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡竹捉,死狀恐怖芜辕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情块差,我是刑警寧澤侵续,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站憨闰,受9級(jí)特大地震影響状蜗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鹉动,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一轧坎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泽示,春花似錦缸血、人聲如沸蜜氨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽记劝。三九已至,卻和暖如春族扰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背定欧。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工渔呵, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砍鸠。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓扩氢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爷辱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子录豺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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

  • Java 1.5發(fā)行版本新增了兩個(gè)引用類型家族:枚舉類型(Enumerate類)和注解類型(Annotation接...
    Timorous閱讀 403評(píng)論 0 0
  • 30弟断、用enum代替int常量 枚舉類型是指由一組固定的常量組成合法值的類型咏花。在java沒有引入枚舉類型前,表示枚...
    Alent閱讀 753評(píng)論 1 5
  • 1. 簡介 1.1 什么是 MyBatis 阀趴? MyBatis 是支持定制化 SQL昏翰、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,429評(píng)論 0 4
  • 不知不覺 陽光刺眼 夏天在大張旗鼓地宣誓主權(quán) 又是一個(gè)夏天 去年的這時(shí)候 每天上班 沒有故事也不知道天空是不是蔚藍(lán)...
    一樹一花音樂閱讀 238評(píng)論 0 0
  • 詠柳-賀知章 碧玉妝成一樹高,萬條垂下綠絲絳刘急。 不知細(xì)葉誰裁出棚菊,二月春風(fēng)似剪刀。 回鄉(xiāng)偶書-賀知章 離別家鄉(xiāng)歲月多...
    走在邊緣閱讀 166評(píng)論 0 0