開心一笑
提出問題
項(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)贊鸠删,頂,歡迎留下寶貴的意見贼陶,多謝支持刃泡!