改善java程式的151個建議--枚舉和註解,java151
83、項目開發中,推薦使用枚舉定義常量,來代替介面常量或類常量
Eg:enum{Spring,Summer,Autumn,Winter;}
枚舉定義常量相對於經常使用的常量類和靜態常量相比的優勢:
1)枚舉常量更簡單:枚舉常量不需要定義枚舉值,int spring=1;枚舉表示的 是一個枚舉項,字面含義不同,其他常量必須是一個類型;
2)枚舉常量屬於穩態型
3)枚舉具有內建的方法,例如values:獲得所有值的集合,可用於遍曆,ordinal: 獲得排序值,compareTo比較方法等;
4)枚舉可以自訂方法:枚舉常量不僅可以定義靜態方法,還可以定義非靜 態方法,還能夠從根本上杜絕常量類被執行個體化
缺點:枚舉類型是不能有繼承的,枚舉常量定義完畢後,除非修改重構,否則無法做擴充。
枚舉類型的遍曆:
for(Season s:Season.values()){System.out.println(s);}
84、使用建構函式協助描述枚舉項
enum Season{//通過構造方法可以為枚舉項添加描述和其他定義Spring("春","春暖花開"),Summer("夏","豔陽高照"),Autumn("秋","秋高氣爽"),Winter("冬","雪花飄飄");private String desc;//描述private String other;//其他//添加上述描述和定義必須添加下面所示的構造方法Season(String desc,String other){this.desc=desc;this.other=other;}//獲得描述public String getDesc(){return desc;}//獲得其他public String getOther(){return other;}}
推薦在枚舉定義中為每個枚舉項定義描述,比在介面常量或類常量中增加註釋的方式友好、簡潔
85、小心switch帶來的空值異常
public static void testSwitch(Season s){switch(s){case Spring:System.out.println("春");break;case Summer:System.out.println("夏");break;default:throw new AssertionError();}}
上面代碼,如果做測試:testSwitch(null);會發現在switch(s)處拋出null 指標異常,這是因為java能判斷的switch類型為short、byte、int、char類型,那麼為什麼枚舉類型能編譯通過呢,這是因為編譯器是根據枚舉類型的排序值進行判斷的:Switch(s.ordinal()){case Season.Spring.ordinal()},如果為null值,那麼沒有ordinal方法,肯定會拋null 指標異常,所以解決方案是在該方法中加入是否為null判斷
86、在switch的default代碼塊中增加AssertionError錯誤
Default:throw new AssertionError();
87、使用valueOf前必須進行校正
枚舉類中提供valueOf方法,用於尋找字串值與該參數相等的枚舉項,返回一個枚舉類型的資料
//測試valueOf方法,因為Season不存在SpringTime會拋出//IllegalArgumentException異常資訊public static void testValueOf(){List<String> list=Arrays.asList("Spring","SpringTime");for(String s:list){Season season=Season.valueOf(s);if(season!=null){System.out.println(s);}else{System.out.println("該枚舉類型不存在");}}}
解決方案:
1、在Season.valueOf方法中添加try....catch方法進行捕獲
2、在枚舉類中添加一個判斷是否存在的方法,例如:contains方法,如果存在 該字串信 息,則進行valueOf 轉換為相應的枚舉類型,不存在則不轉換
88、用枚舉實現Factory 方法模式更簡單
89、枚舉項的數量限制在64個以內
Java提供的枚舉集合,由於枚舉類型的執行個體數量固定並且有限,相對來說其效率會比其他Set和Map要高:
EnumSet:其元素必須是某一枚舉的枚舉項
EnumMap:key值必須是某一枚舉的枚舉項
EnumSet儲存枚舉類型資料時候,當枚舉數量小於等於64時,建立一個RegularEnumSet執行個體對象,大於64時則建立一個JunmboEnumSet執行個體對象
public static void testEnumSet(){EnumSet<Season> set1=EnumSet.allOf(Season.class);EnumSet<Season> set2=EnumSet.allOf(Season.class);//枚舉類型Season中小於或等於64個元素,則得到的結果為:class java.util.RegularEnumSetSystem.out.println(set1.getClass());//枚舉類型Season中超過64個元素,則得到的結果為:class java.util.JumboEnumSetSystem.out.println(set2.getClass());}
因為EnumSet提供的實作類別底層都是基本的數字類型操作,其效能肯定比其他的Set類型要好很多,特別是數量少於64的時候,速度飛快.
90、小心註解繼承
元註解:@Inherited,表示一個註解是否可以自動被繼承
91、枚舉和註解結合使用威力更大
//定義角色層級,使用者,管理員,超級管理員enum RoleIdentify{User,Admin,SuperAdmin;}//定義存取權限註解類@Retention(RetentionPolicy.RUNTIME)//元註解,表示該註解的保留層級@Target(ElementType.TYPE)//元註解,表示該註解可以標註在什麼地方@Inherited//元註解,表示該註解會被自動繼承@interface Access{//定義存取層級,預設為管理員RoleIdentify level() default RoleIdentify.Admin;}//使用自己定義的註解@Access(level=RoleIdentify.User)class TestAnnatation{}public class AnnatationTest {public static void main(String[] args) {//測試TestAnnatation test=new TestAnnatation();Access access=test.getClass().getAnnotation(Access.class);System.out.println(access.level());//列印輸出User}}
92、主要@Override不同版本的區別
如下代碼:
interface MyInterface{public void doSomething();}class MyImpl implements MyInterface{@Overridepublic void doSomething() {}public void doTest(List<String> strList){}}
上面代碼在jdk1.6版本上編譯沒有任何問題,但是在jdk1.5版本上編譯上面代碼會出錯誤:The method doSomething of type MyImpl override a superclass...
原因是jdk1.5中的@Override是嚴格遵守覆寫的定義:子類方法與父類方法必須具有相同的方法名稱、輸入參數、輸出參數(允許子類縮小)、存取權限(允許子類擴大),父類必須是一個類,不能是一個介面,否則不能算是覆寫。
所以,如果是jdk1.6版本的項目移植到jdk1.5版本上面,就需要刪除實現介面方法上的@Override註解。