天天看點

閱讀阿裡巴巴Java開發手冊,截取一些需要注意的地方

原文出自  阿裡巴巴Java開發手冊,禁止用于商業用途,違者必究

【推薦】集合初始化時,指定集合初始值大小。 

說明:HashMap 使用 HashMap(int initialCapacity) 初始化, 

正例:initialCapacity = (需要存儲的元素個數 / 負載因子) + 1。注意負載因子(即loader factor)預設為 0.75,如果暫時無法确定初始值大小,請設定為 16(即預設值)。 

反例:HashMap 需要放置 1024 個元素,由于沒有設定容量初始大小,随着元素不斷增加,容量 7 次被迫擴大,resize 需要重建hash 表,嚴重影響性能。    原來多次擴大Map容量會影響效率。

【強制】使用工具類 Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關的方法,它的add/remove/clear 方法會抛出 UnsupportedOperationException 異常。 

說明:asList 的傳回對象是一個 Arrays 内部類,并沒有實作集合的修改方法。Arrays.asList

展現的是擴充卡模式,隻是轉換接口,背景的資料仍是數組。 

    String[] str = new String[] { "you", "wu" }; 

    List list = Arrays.asList(str); 

第一種情況:list.add("yangguanbao"); 運作時異常。 

第二種情況:str[0] = "gujin"; 那麼 list.get(0)也會随之修改。

【推薦】循環體内,字元串的連接配接方式,使用 StringBuilder 的 append 方法進行擴充。 

說明:反編譯出的位元組碼檔案顯示每次循環都會 new 出一個 StringBuilder 對象,然後進行append 操作,最後通過 toString 方法傳回String 對象,造成記憶體資源浪費。 

反例: 

String str = "start";      

    for (int i = 0; i < 100; i++) {          

str = str + "hello";      

}  

【推薦】 類内方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter/setter方法。 

說明:公有方法是類的調用者和維護者最關心的方法,首屏展示最好;保護方法雖然隻是子類關心,也可能是“模闆設計模式”下的核心方法;而私有方法外部一般不需要特别關心,是一個黑盒實作;因為承載的資訊價值較低,所有 Service 和DAO的getter/setter 方法放在類體最後。

學習一個新名詞,黑盒實作。

關于基本資料類型與包裝資料類型的使用标準如下: 

 1) 【強制】所有的 POJO 類屬性必須使用包裝資料類型。 

 2) 【強制】RPC 方法的傳回值和參數必須使用包裝資料類型。 

 3) 【推薦】所有的局部變量使用基本資料類型。 

 說明:POJO 類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行指派,任何NPE 問題,或者入庫檢查,都由使用者來保證。 

 正例:資料庫的查詢結果可能是 null,因為自動拆箱,用基本資料類型接收有 NPE 風險。 

 反例:比如顯示成交總額漲跌情況,即正負 x%,x 為基本資料類型,調用的 RPC 服務,調用不成功時,傳回的是預設值,頁面顯示為0%,這是不合理的,應該顯示成中劃線。是以包裝資料類型的null 值,能夠表示額外的資訊,如:遠端調用失敗,異常退出。 

【參考】各層命名規約:  

A) Service/DAO 層方法命名規約 

 1) 擷取單個對象的方法用 get 做字首。 

 2) 擷取多個對象的方法用 list 做字首。 

 3) 擷取統計值的方法用 count 做字首。 

 4) 插入的方法用 save/insert 做字首。 

 5) 删除的方法用 remove/delete 做字首。 

 6) 修改的方法用 update 做字首。 

B) 領域模型命名規約 

 1) 資料對象:xxxDO,xxx 即為資料表名。 

 2) 資料傳輸對象:xxxDTO,xxx 為業務領域相關的名稱。 

 3) 展示對象:xxxVO,xxx 一般為網頁名稱。 

 4) POJO 是 DO/DTO/BO/VO 的統稱,禁止命名成 xxxPOJO。

【推薦】使用entrySet 周遊Map 類集合KV,而不是keySet 方式進行周遊。 

說明:keySet 其實是周遊了 2次,一次是轉為 Iterator 對象,另一次是從 hashMap 中取出key 所對應的 value。而 entrySet 隻是周遊了一次就把 key 和value 都放到了entry 中,效率更高。如果是JDK8,使用Map.foreach方法。 

正例:values()傳回的是 V 值集合,是一個list 集合對象;keySet()傳回的是K 值集合,是一個Set 集合對象;entrySet()傳回的是K-V 值組合集合。 

                Map<String,String> testMap = new HashMap<String, String>();
		
		Iterator<Entry<String, String>> iterator = testMap.entrySet().iterator();
		
		while(iterator.hasNext()){
			Entry<String, String> next = iterator.next();
			String key = next.getKey();
			String value = next.getValue();
		}           

【參考】合理利用好集合的有序性(sort)和穩定性(order),避免集合的無序性(unsort)和不穩定性(unorder)帶來的負面影響。 

說明:有序性是指周遊的結果是按某種比較規則依次排列的。穩定性指集合每次周遊的元素次序是一定的。如:ArrayList 是 order/unsort;HashMap 是unorder/unsort;TreeSet 是order/sort。

【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式建立線程。 

說明:使用線程池的好處是減少在建立和銷毀線程上所花的時間以及系統資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統建立大量同類線程而導緻消耗完記憶體或者“過度切換”的問題。

【強制】線程池不允許使用 Executors 去建立,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學更加明确線程池的運作規則,規避資源耗盡的風險。 

說明:Executors 傳回的線程池對象的弊端如下: 

1)FixedThreadPool和 SingleThreadPool: 

 允許的請求隊列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,進而導緻 OOM。 

2)CachedThreadPool和 ScheduledThreadPool: 

 允許的建立線程數量為 Integer.MAX_VALUE,可能會建立大量的線程,進而導緻 OOM。

【強制】高并發時,同步調用應該去考量鎖的性能損耗。能用無鎖資料結構,就不要用鎖;能鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。 

說明:盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調用 RPC 方法。 

【參考】下列情形,需要進行參數校驗: 

 1) 調用頻次低的方法。 

 2) 執行時間開銷很大的方法。此情形中,參數校驗時間幾乎可以忽略不計,但如果因為參數錯誤導緻中間執行回退,或者錯誤,那得不償失。 

 3) 需要極高穩定性和可用性的方法。 

 4) 對外提供的開放接口,不管是 RPC/API/HTTP 接口。 

 5) 敏感權限入口。

【強制】注意 Math.random() 這個方法傳回是 double 類型,注意取值的範圍 0≤x<1(能夠取到零值,注意除零異常),如果想擷取整數類型的随機數,不要将 x 放大10的若幹倍然後取整,直接使用Random 對象的 nextInt 或者nextLong 方法。 

【強制】對大段代碼進行 try-catch,這是不負責任的表現。catch時請厘清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼。對于非穩定代碼的 catch 盡可能進行區分異常類型,再做對應的異常處理。

【強制】捕獲異常是為了處理它,不要捕獲了卻什麼都不處理而抛棄之,如果不想處理它,請将該異常抛給它的調用者。最外層的業務使用者,必須處理異常,将其轉化為使用者可以了解的内容。

【參考】在代碼中使用“抛異常”還是“傳回錯誤碼”,對于公司外的 http/api 開放接口必須使用“錯誤碼”;而應用内部推薦異常抛出;跨應用間RPC 調用優先考慮使用Result 方式,封裝 isSuccess()方法、“錯誤碼”、“錯誤簡短資訊”。 

說明:關于RPC 方法傳回方式使用 Result 方式的理由: 

 1)使用抛異常傳回方式,調用方如果沒有捕獲到就會産生運作時錯誤。 

 2)如果不加棧資訊,隻是 new 自定義異常,加入自己的了解的 error message,對于調用端解決問題的幫助不會太多。如果加了棧資訊,在頻繁調用出錯的情況下,資料序列化和傳輸的性能損耗也是問題。 

【強制】表名、字段名必須使用小寫字母或數字,禁止出現數字開頭,禁止兩個下劃線中間隻出現數字。資料庫字段名的修改代價很大,因為無法進行預釋出,是以字段名稱需要慎重考慮。 

說明:MySQL 在Windows 下不區分大小寫,但在 Linux 下預設是區分大小寫。是以,資料庫名、表名、字段名,都不允許出現任何大寫字母,避免節外生枝。 

正例:aliyun_admin,rdc_config,level3_name 

反例:AliyunAdmin,rdcConfig,level_3_name 

【推薦】字段允許适當備援,以提高查詢性能,但必須考慮資料一緻。備援字段應遵循: 

 1)不是頻繁修改的字段。 

 2)不是 varchar 超長字段,更不能是 text字段。 

正例:商品類目名稱使用頻率高,字段長度短,名稱基本一成不變,可在相關聯的表中備援存儲類目名稱,避免關聯查詢。

繼續閱讀