阿里巴巴Java開發手冊閱讀筆記--編程規約

本文是對《阿里巴巴Java開發手冊》閱讀過程的札記(記錄我覺得重要的知識點以及我在實際開發過程中對這些問題的理解)

一、OOP規約篇

1、Object的equals方法容易拋空指針異常,應使用常量或確定有值的對象來調用equals。
正例:“test”.equals(object) 反例:object.equals(“test”)

2、所有的相同類型的包裝類對象之間值的比較,全部使用 equals 方法比較。
說明:對於 Integer var =?在-128 至 127 之間的賦值, Integer 對象是在
IntegerCache . cache 產生,會複用已有對象,這個區間內的 Integer 值可以直接使用==進行判斷,但是這個區間之外的所有數據,都會在堆上產生,並不會複用已有對象,這是一個大坑,推薦使用 equals 方法進行判斷。
這裏需要注意,Integer對象的值在-128 至 127範圍內,會用常量區的值,否則就會生成新對象,很坑!

    Integer a = 120,b = 120,c = 150,d = 150;
    System.out.println(a == b);
    System.out.println(c == d);
    結果爲:true    false

3、關於基本數據類型與包裝數據類型的使用標準如下:
1 ) 所有的 POJO 類屬性必須使用包裝數據類型。
2 ) RPC 方法的返回值和參數必須使用包裝數據類型。
3 ) 所有的局部變量【推薦】使用基本數據類型。
說明: POJO 類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何NPE 問題,或者入庫檢查,都由使用者來保證。
正例:數據庫的查詢結果可能是 null ,因爲自動拆箱,用基本數據類型接收有 NPE 風險。
反例:比如顯示成交總額漲跌情況,即正負 x %, x 爲基本數據類型,調用的 RPC 服務,調用不成功時,返回的是默認值,頁面顯示:0%,這是不合理的,應該顯示成中劃線-。所以包裝數據類型的 null 值,能夠表示額外的信息,如:遠程調用失敗,異常退出。
POJO類:(Plain Ordinary Java Object)簡單的Java對象,實際就是普通JavaBeans,是爲了避免和EJB混淆所創造的簡稱。
NPE問題:java.lang.NullPointerException:NPE ,空值異常。

4、定義 DO / DTO / VO 等 POJO 類時,不要設定任何屬性默認值。
反例: POJO 類的 gmtCreate 默認值爲 new Date(); 但是這個屬性在數據提取時並沒有置入具體值,在更新其它字段時又附帶更新了此字段,導致創建時間被修改成當前時間。

5、序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失敗 ,實現Serializable接口時,會自動生成唯一的UID,不要更改; 如果完全不兼容升級,避免反序列化混亂,那麼請修改 serialVersionUID 值。
說明:注意 serialVersionUID 不一致會拋出序列化運行時異常。

6、POJO 類必須寫 toString 方法。使用 IDE 的中工具: source > generate toString時,如果繼承了另一個 POJO 類,注意在前面加一下 super . toString 。說明:在方法執行拋出異常時,可以直接調用 POJO 的 toString() 方法打印其屬性值,便於排查問題。其實,寫POJO類時,一般默認都要寫私有化字段,get/set方法,toString方法。無參構造器不寫即默認省略

7、類內方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter / setter方法。
說明(一般編碼規範):公有方法是類的調用者和維護者最關心的方法,首屏展示最好 ; 保護方法雖然只是子類關心,也可能是“模板設計模式”下的核心方法 ; 而私有方法外部一般不需要特別關心,是一個黑盒實現 ; 因爲方法信息價值較低,所有 Service 和 DAO 的 getter / setter 方法放在類體最後。

8、循環體內,字符串的聯接方式,使用 StringBuilder 的 append 方法進行擴展,切勿使用String對象直接用“+”拼接。
說明:反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,然後進行append 操作,最後通過 toString 方法返回 String 對象,造成內存資源浪費。

9、慎用 Object 的 clone 方法來拷貝對象。沒用過這個方法,覺得很厲害的樣子,Mark一下、
說明:對象的 clone 方法默認是淺拷貝,若想實現深拷貝需要重寫 clone 方法實現屬性對象的拷貝。

10、類成員與方法訪問控制從嚴:比喻很到位
1 ) 如果不允許外部直接通過 new 來創建對象,那麼構造方法必須是 private 。
2 ) 工具類不允許有 public 或 default 構造方法。
3 ) 類非 static 成員變量並且與子類共享,必須是 protected 。
4 ) 類非 static 成員變量並且僅在本類使用,必須是 private 。
5 ) 類 static 成員變量如果僅在本類使用,必須是 private 。
6 ) 若是 static 成員變量,必須考慮是否爲 final 。
7 ) 類成員方法只供類內部調用,必須是 private 。
8 ) 類成員方法只對繼承類公開,那麼限制爲 protected 。
說明:任何類、方法、參數、變量,嚴控訪問範圍。過寬泛的訪問範圍,不利於模塊解耦。思
考:如果是一個 private 的方法,想刪除就刪除,可是一個 public 的 Service 方法,或者一
個 public 的成員變量,刪除一下,不得手心冒點汗嗎?變量像自己的小孩,儘量在自己的視
線內,變量作用域太大,如果無限制的到處跑,那麼你會擔心你的孩子。

二、集合問題處理篇

1、關於 hashCode 和 equals 的處理,遵循如下規則:

1) 只要重寫 equals ,就必須重寫 hashCode 。
2) 因爲 Set 存儲的是不重複的對象,依據 hashCode 和 equals 進行判斷,所以 Set 存儲的
對象必須重寫這兩個方法。
3) 如果自定義對象做爲 Map 的鍵,那麼必須重寫 hashCode 和 equals 。
正例: String 重寫了 hashCode 和 equals 方法,所以我們可以非常愉快地使用 String 對象作爲 key 來使用。

2、ArrayList 的 subList 結果不可強轉成 ArrayList ,否則會拋出 ClassCastException
異常: java . util . RandomAccessSubList cannot be cast to java . util . ArrayList ;
說明: subList 返回的是 ArrayList 的內部類 SubList ,並不是 ArrayList ,而是ArrayList 的一個視圖,對於 SubList 子列表的所有操作最終會反映到原列表上。

3、在 subList 場景中,高度注意對原集合元素個數的修改,會導致子列表的遍歷、增加、刪除均產生 ConcurrentModificationException 異常。

4、使用集合轉數組的方法,必須使用集合的 toArray(T[] array) ,傳入的是類型完全一樣的數組,大小就是 list . size() 。
反例:直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[] 類,若強轉其它類型數組將出現 ClassCastException 錯誤。
正例:

List<String> list = new ArrayList<String>(2);
list.add("FLY");
list.add("fly");
String[] array = new String[list.size()];
array = list.toArray(array);

說明:使用 toArray 帶參方法,入參分配的數組空間不夠大時, toArray 方法內部將重新分配內存空間,並返回新數組地址 ; 如果數組元素大於實際所需,下標爲 [ list . size() ] 的數組元素將被置爲 null ,其它數組元素保持原值,因此最好將方法入參數組大小定義與集合元素個數一致。

5、使用工具類 Arrays . asList() 把數組轉換成集合時,不能使用其修改集合相關的方法,它的 add / remove / clear 方法會拋出 UnsupportedOperationException 異常。
說明: asList 的返回對象是一個 Arrays 內部類,並沒有實現集合的修改方法。 Arrays . asList
體現的是適配器模式,只是轉換接口,後臺的數據仍是數組。

String[] str = new String[] { "a", "b" };
List list = Arrays.asList(str);

第一種情況: list.add(“c”); 運行時異常。
第二種情況: str[0]= “Timor”; 那麼 list.get(0) 也會隨之修改。

6、泛型通配符<? extends T >來接收返回的數據,此寫法的泛型集合不能使用 add 方法。
說明:蘋果裝箱後返回一個<? extends Fruits >對象,此對象就不能往裏加任何水果,包括蘋果。

7、不要在 foreach 循環裏進行元素的 remove / add 操作。 remove 元素請使用 Iterator方式,如果併發操作,需要對 Iterator 對象加鎖。
反例:

List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
    if("1".equals(temp)){
    a.remove(temp);
    }
}
可以刪除1,輸出[2],把判斷條件的1換成2之後就會報異常。
異常信息:java.util.ConcurrentModificationException

正例:

Iterator<String> it = a.iterator();
while(it.hasNext()){
String temp = it.next();
if(刪除元素的條件){
    it.remove();
    }
}

8、遍歷Map集合時,儘量使用entrySet得到所有KV的集合,再進行遍歷,對大數據量的集合遍歷有速度優勢。

9、高度注意 Map 類集合 K / V 能不能存儲 null 值的情況,如下:
這裏寫圖片描述

10、利用 Set 元素唯一的特性,可以快速對一個集合進行去重操作,避免使用 List 的contains 方法進行遍歷、對比、去重操作。
關於集合的遍歷及其他問題請參照我的其他博文

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章