阿里Java開發手冊之編程規約


對於程序猿來說,編程規范能夠養成良好的編程習慣,提高代碼質量,減少溝通成本。就在2月9號,阿里出了一份Java開發手冊(正式版),分為編程規約。異常日志。MySQL規約,project規約。安全規約五個章節。

這里我依據阿里的編程規約,重點記錄(黑色加粗部分)自己還未做好的一些規范,同一時候方便查閱。


編程規約

一、命名規約

  • 【強制】代碼中的命名均不能下面划線或美元符號開始。也不能下面划線或美元符號結束。

    反例: _name / __name / $Object / name_ / name$ / Object$ 
        
        
       
       
               
    • 1
    • 1
  • 【強制】 代碼中的命名嚴禁使用拼音與英文混合的方式。更不同意直接使用中文的方式。 說明:正確的英文拼寫和語法能夠讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式 也要避免採用。

    反例: DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變量 = 3 正例: alibaba / taobao / youku / hangzhou 等國際通用的名稱。可視同英文。
        
        
       
       
               
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3
  • 【強制】類名使用 UpperCamelCase 風格。必須遵從駝峰形式。但下面情形例外:(領域模型 的相關命名)DO / BO / DTO / VO 等

    正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion 反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3
  • 【強制】方法名、參數名、成員變量、局部變量都統一使用 lowerCamelCase 風格。必須遵從 駝峰形式

    正例: localValue / getHttpMessage() / inputUserId
        
        
       
       
               
    • 1
    • 1
  • 【強制】常量命名所有大寫。單詞間用下划線隔開,力求語義表達完整清楚,不要嫌名字長

    正例: MAX_STOCK_COUNT 反例: MAX_COUNT 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3
  • 【強制】抽象類命名使用 Abstract 或 Base 開頭;異常類命名使用 Exception 結尾。測試類 命名以它要測試的類的名稱開始,以 Test 結尾

  • 【強制】中括號是數組類型的一部分,數組定義例如以下:String[] args

    反例:請勿使用 String args[]的方式來定義。 
        
        
       
       
               
    • 1
    • 1
  • 【強制】POJO 類中布爾類型的變量,都不要加 is。否則部分框架解析會引起序列化錯誤

    反例:定義為基本數據類型 boolean isSuccess。的屬性。它的方法也是 isSuccess()。RPC 框架在反向解析的時候。“以為”相應的屬性名稱是 success。導致屬性獲取不到。進而拋出異 常。 
        
        
       
       
               
    • 1
    • 1
  • 【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用 單數形式。可是類名假設有復數含義,類名能夠使用復數形式

    正例: 應用工具類包名為 com.alibaba.open.util、類名為 MessageUtils(此規則參考 spring 的框架結構) 
        
        
       
       
               
    • 1
    • 1
  • 【強制】杜絕全然不規范的縮寫,避免望文不知義

    反例: AbstractClass“縮寫”命名成 AbsClass。condition“縮寫”命名成 condi,此類 任意縮寫嚴重減少了代碼的可閱讀性。

    • 1
    • 1
  • 【推薦】假設使用到了設計模式,建議在類名體現出詳細的設計模式

    說明:將設計模式體如今名字中,有利於閱讀者高速理解架構設計思想。

    正例:public class OrderFactory; public class LoginProxy; public class ResourceObserver;

    • 1
    • 2
    • 3
    • 4
    • 5
    • 1
    • 2
    • 3
    • 4
    • 5
  • 【推薦】接口類中的方法和屬性不要加不論什么修飾符號(public 也不要加),保持代碼的簡潔 性,並加上有效的 Javadoc 凝視。盡量不要在接口里定義變量。假設一定要定義變量。肯定是與接口方法相關,而且是整個應用的基礎常量

    正例:接口方法簽名:void f(); 接口基礎常量表示:String COMPANY = "alibaba"; 反例:接口方法定義:public abstract void f(); 說明:JDK8 中接口同意有默認實現。那么這個 default 方法,是對全部實現類都有價值的默 認實現。 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 接口和實現類的命名有兩套規則

    • 【強制】對於 Service 和 DAO 類,基於 SOA 的理念,暴露出來的服務一定是接口,內部 的實現類用 Impl 的后綴與接口差別
    正例:CacheServiceImpl 實現 CacheService 接口
        
        
       
       
               
    • 1
    • 1
    • 【推薦】假設是形容能力的接口名稱。取相應的形容詞做接口名(一般是–able 的形式)
    正例:AbstractTranslator 實現 Translatable
        
        
       
       
               
    • 1
    • 1
  • 【參考】枚舉類名建議帶上Enum后綴,枚舉成員名稱須要全大寫,單詞間用下划線隔開

    說明:枚舉事實上就是特殊的常量類。且構造方法被默認強制是私有。

    正例:枚舉名字:DealStatusEnum,成員名稱:SUCCESS / UNKOWN_REASON

    • 1
    • 2
    • 3
    • 1
    • 2
    • 3
  • 【參考】各層命名規約

    • Service/DAO 層方法命名規約

      • 獲取單個對象的方法用 get 做前綴
      • 獲取多個對象的方法用 list 做前綴
      • 獲取統計值的方法用 count 做前綴
      • 插入的方法用 save(推薦)或 insert 做前綴
      • 刪除的方法用 remove(推薦)或 delete 做前綴
      • 改動的方法用 update 做前綴
    • 領域模型命名規約

      • 數據對象:xxxDO,xxx 即為數據表名
      • 傳輸數據對象:xxxDTO。xxx 為業務領域相關的名稱
      • 展示對象:xxxVO。xxx 一般為網頁名稱。
      • POJO 是 DO/DTO/BO/VO 的統稱,禁止命名成 xxxPOJO

二、常量定義

  • 【強制】不同意出現不論什么魔法值(即未經定義的常量)直接出如今代碼中。

     反例: String key="Id#taobao_"+tradeId; cache.put(key, value); 
        
        
       
       
               
    • 1
    • 1
  • 【強制】long 或者 Long 初始賦值時,必須使用大寫的 L。不能是小寫的 l,小寫easy跟數字 1 混淆。造成誤解

    說明:Long a = 2l; 寫的是數字的 21,還是 Long 型的 2? 
        
        
       
       
               
    • 1
    • 1
  • 【推薦】不要使用一個常量類維護全部常量,應該按常量功能進行歸類,分開維護。

    如:緩存 相關的常量放在類:CacheConsts 下。系統配置相關的常量放在類:ConfigConsts 下。 說明:大而全的常量類,非得使用查找功能才干定位到改動的常量,不利於理解和維護

  • 【推薦】常量的復用層次有五層:跨應用共享常量、應用內共享常量、子project內共享常量、包 內共享常量、類內共享常量

    • 跨應用共享常量:放置在二方庫中。一般是 client.jar 中的 constant 文件夾下

    • 應用內共享常量:放置在一方庫的 modules 中的 constant 文件夾下

    • 子project內部共享常量:即在當前子project的 constant 文件夾下

    • 包內共享常量:即在當前包下單獨的 constant 文件夾下

    • 類內共享常量:直接在類內部 private static final 定義

  • 【推薦】假設變量值僅在一個范圍內變化用 Enum 類。假設還帶有名稱之外的延伸屬性,必須 使用 Enum 類,以下正例中的數字就是延伸信息。表示星期幾

    正例:public Enum{ MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);} 
        
        
       
       
               
    • 1
    • 1

三、格式規約

  • 【強制】大括號的使用約定。

    假設是大括號內為空,則簡潔地寫成{}就可以,不須要換行;假設 是非空代碼塊則:

    • 左大括號前不換行。
    • 左大括號后換行。

    • 右大括號前換行。

    • 右大括號后還有 else 等代碼則不換行;表示終止右大括號后必須換行。
  • 【強制】 左括號和后一個字符之間不出現空格。相同,右括號和前一個字符之間也不出現空格。

  • 【強制】if/for/while/switch/do 等保留字與左右括號之間都必須加空格。

  • 【強制】不論什么運算符左右必須加一個空格。

    說明:運算符包含賦值運算符=、邏輯運算符&&、加減乘除符號、三目執行符等
        
        
       
       
               
    • 1
    • 1
  • 【強制】縮進採用 4 個空格,禁止使用 tab 字符

    說明:假設使用 tab 縮進。必須設置 1tab4 個空格。

    IDEA 設置 tab4 個空格時, 請勿勾選 Use tab character;而在 eclipse 中。必須勾選 insert spaces for tabs

    • 1
    • 1
  • 【強制】單行字符數限制不超過 120 個,超出須要換行,換行時遵循例如以下原則:

    • 第二行相對第一行縮進 4 個空格。從第三行開始,不再繼續縮進,參考演示樣例。

    • 運算符與下文一起換行。

    • 方法調用的點符號與下文一起換行

    • 在多個參數超長。逗號后進行換行

    • 在括號前不要換行,見反例

    正例: StringBuffer sb = new StringBuffer(); //超過 120 個字符的情況下,換行縮進 4 個空格,而且方法前的點符號一起換行 sb.append("zi").append("xin")... .append("huang")... .append("huang")... .append("huang"); 反例: StringBuffer sb = new StringBuffer(); //超過 120 個字符的情況下,不要在括號前換行 sb.append("zi").append("xin")...append ("huang"); //參數非常多的方法調用可能超過 120 個字符,不要在逗號前換行 method(args1, args2, args3, ... , argsX); 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
  • 【強制】IDE 的 text file encoding 設置為 UTF-8; IDE 中文件的換行符使用 Unix 格式。 不要使用 windows 格式
  • 【推薦】沒有必要添加若干空格來使某一行的字符與上一行的對應字符對齊。

    正例: int a = 3; long b = 4L; float c = 5F; StringBuffer sb = new StringBuffer(); 說明:添加 sb 這個變量。假設須要對齊,則給 a、b、c 都要添加幾個空格,在變量比較多的 情況下,是一種累贅的事情。 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 【推薦】方法體內的運行語句組、變量的定義語句組、不同的業務邏輯之間或者不同的語義 之間插入一個空行。同樣業務邏輯和語義之間不須要插入空行。

四、OOP規約

  • 【強制】避免通過一個類的對象引用訪問此類的靜態變量或靜態方法,無謂添加編譯器解析成 本。直接用類名來訪問就可以

  • 【強制】全部的覆寫方法,必須加@Override 注解。

    反例:getObject()get0bject()的問題。一個是字母的 O,一個是數字的 0,加@Override 能夠准確推斷是否覆蓋成功。另外,假設在抽象類中對方法簽名進行改動,事實上現類會立即編 譯報錯。

    • 1
    • 1
  • 【強制】同樣參數類型,同樣業務含義,才干夠使用 Java 的可變參數,避免使用 Object

    說明:可變參數必須放置在參數列表的最后。(提倡同學們盡量不用可變參數編程) 正例:public User getUsers(String type, Integer... ids) 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 1
    • 2
    • 3
  • 【強制】對外暴露的接口簽名。原則上不同意改動方法簽名。避免對接口調用方產生影響。接 口過時必須加@Deprecated 注解。並清晰地說明採用的新接口或者新服務是什么

  • 【強制】不能使用過時的類或方法

    說明:java.net.URLDecoder 中的方法 decode(String encodeStr) 這種方法已經過時,應 該使用雙參數 decode(String source, String encode)。

    接口提供方既然明白是過時接口, 那么有義務同一時候提供新的接口。作為調用方來說,有義務去考證過時方法的新實現是什么。

    • 1
    • 1
  • 【強制】Object 的 equals 方法easy拋空指針異常,應使用常量或確定有值的對象來調用 equals

    正例: "test".equals(object); 反例: object.equals("test"); 說明:推薦使用 java.util.Objects#equals (JDK7 引入的工具類) 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 1
    • 2
    • 3
    • 4
    • 5
  • 【強制】所有的同樣類型的包裝類對象之間值的比較。所有使用 equals 方法比較

    說明:對於 Integer var=?-128127 之間的賦值,Integer 對象是在 IntegerCache.cache 產生。會復用已有對象,這個區間內的 Integer 值能夠直接使用==進行 推斷,可是這個區間之外的全部數據,都會在堆上產生。並不會復用已有對象。這是一個大坑, 推薦使用 equals 方法進行推斷
        
        
       
       
               
    • 1
    • 1
  • 【強制】關於基本數據類型與包裝數據類型的使用標准例如以下:

    • 全部的 POJO 類屬性必須使用包裝數據類型。

    • RPC 方法的返回值和參數必須使用包裝數據類型。

    • 全部的局部變量【推薦】使用基本數據類型

  • 【強制】定義 DO/DTO/VO 等 POJO 類時,不要設定不論什么屬性默認值

  • 【強制】序列化類新增屬性時。請不要改動 serialVersionUID 字段。避免反序列失敗;如 果全然不兼容升級,避免反序列化混亂。那么請改動 serialVersionUID 值。

  • 【強制】構造方法里面禁止增加不論什么業務邏輯。假設有初始化邏輯,請放在 init 方法中

  • 【強制】POJO 類必須寫 toString 方法。使用 IDE 的中工具:source> generate toString 時,假設繼承了還有一個 POJO 類,注意在前面加一下 super.toString。

  • 【推薦】使用索引訪問用 String 的 split 方法得到的數組時。需做最后一個分隔符后有無 內容的檢查。否則會有拋 IndexOutOfBoundsException 的風險。

  • 【推薦】當一個類有多個構造方法,或者多個同名方法。這些方法應該按順序放置在一起, 便於閱讀。

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

  • 【推薦】setter 方法中。參數名稱與類成員變量名稱一致,this.成員名=參數名。在 getter/setter 方法中,盡量不要添加業務邏輯,添加排查問題的難度

    反例: public Integer getData(){ if(true) { return data + 100; } else { return data - 100; } } 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 【推薦】循環體內。字符串的聯接方式,使用 StringBuilder 的 append 方法進行擴展

    反例: String str = "start"; for(int i=0; i<100; i++){ str = str + "hello"; } 說明:反編譯出的字節碼文件顯示每次循環都會 new 出一個 StringBuilder 對象,然后進行 append 操作,最后通過 toString 方法返回 String 對象,造成內存資源浪費。 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 【推薦】final 可提高程序響應效率。聲明成 final 的情況

    • 不須要又一次賦值的變量,包含類屬性、局部變量。

    • 對象參數前加final,表示不同意改動引用的指向
    • 類方法確定不同意被重寫
  • 【推薦】慎用 Object 的 clone 方法來拷貝對象

    說明:對象的 clone 方法默認是淺拷貝。若想實現深拷貝須要重寫 clone 方法實現屬性對象 的拷貝。 
        
        
       
       
               
    • 1
    • 1
  • 【推薦】類成員與方法訪問控制從嚴

    • 假設不同意外部直接通過 new 來創建對象,那么構造方法必須是 private。

    • 工具類不同意有 public 或 default 構造方法

    • 類非 static 成員變量而且與子類共享。必須是 protected。

    • 類非 static 成員變量而且僅在本類使用,必須是 private

    • 類 static 成員變量假設僅在本類使用。必須是 private

    • 若是 static 成員變量。必須考慮是否為 final

    • 類成員方法僅僅供類內部調用,必須是 private

    • 類成員方法僅僅對繼承類公開,那么限制為 protected

      說明:不論什么類、方法、參數、變量。嚴控訪問范圍。過寬泛的訪問范圍。不利於模塊解耦
            
            
           
           
                   
      • 1
      • 1

五、集合處理

  • 【強制】關於 hashCode 和 equals 的處理。遵循例如以下規則:

    • 僅僅要重寫 equals,就必須重寫 hashCode
    • 由於 Set 存儲的是不反復的對象,根據 hashCode 和 equals 進行推斷,所以 Set 存儲的 對象必須重寫這兩個方法。
    • 假設自己定義對象做為 Map 的鍵。那么必須重寫 hashCode 和 equals
  • 【強制】 ArrayList的subList結果不可強轉成ArrayList,否則會拋出ClassCastException 異常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList

    說明:subList 返回的是 ArrayList 的內部類 SubList。並非 ArrayList ,而是 ArrayList 的一個視圖,對於 SubList 子列表的全部操作終於會反映到原列表上。

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

  • 【強制】使用集合轉數組的方法,必須使用集合的 toArray(T[] array),傳入的是類型全然 一樣的數組。大小就是 list.size()

反例:直接使用 toArray 無參方法存在問題,此方法返回值僅僅能是 Object[]類,若強轉其他 類型數組將出現 ClassCastException 錯誤。 正例: List<String> list = new ArrayList<String>(2); list.add("guan"); list.add("bao"); String[] array = new String[list.size()]; array = list.toArray(array); 說明:使用 toArray 帶參方法,入參分配的數組空間不夠大時,toArray 方法內部將又一次分配 內存空間。並返回新數組地址。假設數組元素大於實際所需。下標為[ list.size() ]的數組 元素將被置為 null,其他數組元素保持原值,因此最好將方法入參數組大小定義與集合元素個數一致
  
  
 
 
         
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 【強制】使用工具類 Arrays.asList()把數組轉換成集合時,不能使用其改動集合相關的方 法,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常
說明:asList 的返回對象是一個 Arrays 內部類。並沒有實現集合的改動方法。Arrays.asList 體現的是適配器模式,僅僅是轉換接口,后台的數據仍是數組。

  • 1
  • 1
  • 【強制】泛型通配符
說明:蘋果裝箱后返回一個<?

  • 1
  • 1

extends Fruits>對象。此對象就不能往里加不論什么水果,包含 蘋果

  • 【強制】不要在 foreach 循環里進行元素的 remove/add 操作。

    remove 元素請使用 Iterator 方式。假設並發操作,須要對 Iterator 對象加鎖

  • 【強制】 在 JDK7 版本號以上,Comparator 要滿足自反性,傳遞性,對稱性,不然 Arrays.sort, Collections.sort 會報 IllegalArgumentException 異常

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

    說明:ArrayList 盡量使用 ArrayList(int initialCapacity) 初始化。 
        
        
       
       
               
    • 1
    • 1
  • 【推薦】使用 entrySet 遍歷 Map 類集合 KV。而不是 keySet 方式進行遍歷

    說明:keySet 事實上是遍歷了 2 次,一次是轉為 Iterator 對象,還有一次是從 hashMap 中取出 key 所相應的 value。而 entrySet 僅僅是遍歷了一次就把 key 和 value 都放到了 entry 中。效 率更高。

    假設是 JDK8,使用 Map.foreach 方法

    • 1
    • 1
  • 【推薦】高度注意 Map 類集合 K/V 能不能存儲 null 值的情況,例如以下表格

    image

    反例: 因為 HashMap 的干擾,非常多人覺得 ConcurrentHashMap 是能夠置入 null 值。注意存儲 null 值時會拋出 NPE 異常
        
        
       
       
               
    • 1
    • 1
  • 【參考】合理利用好集合的有序性(sort)和穩定性(order),避免集合的無序性(unsort)和 不穩定性(unorder)帶來的負面影響。
  • 【參考】利用 Set 元素唯一的特性,能夠高速對一個集合進行去重操作。避免使用 List 的 contains 方法進行遍歷、對照、去重操作

六、並發處理

  • 【強制】獲取單例對象須要保證線程安全,當中的方法也要保證線程安全

  • 【強制】創建線程或線程池時請指定有意義的線程名稱,方便出錯時回溯

    正例: public class TimerTaskThread extends Thread { public TimerTaskThread(){ super.setName("TimerTaskThread"); ... } } 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 【強制】線程資源必須通過線程池提供。不同意在應用中自行顯式創建線程

    說明:使用線程池的優點是降低在創建和銷毀線程上所花的時間以及系統資源的開銷。解決資源不足的問題。假設不使用線程池,有可能造成系統創建大量同類線程而導致消耗完內存或者 “過度切換”的問題。
        
        
       
       
               
    • 1
    • 1
  • 【強制】線程池不同意使用 Executors 去創建。而是通過 ThreadPoolExecutor 的方式,這樣 的處理方式讓寫的同學更加明白線程池的執行規則,規避資源耗盡的風險

    說明:Executors 返回的線程池對象的弊端例如以下: 1、FixedThreadPool 和 SingleThreadPool: 同意的請求隊列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導致 OOM。

    2、CachedThreadPool 和 ScheduledThreadPool: 同意的創建線程數量為 Integer.MAX_VALUE,可能會創建大量的線程。從而導致 OOM

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 【強制】SimpleDateFormat 是線程不安全的類。一般不要定義為 static 變量,假設定義為 static,必須加鎖。或者使用 DateUtils 工具類

    說明:假設是 JDK8 的應用,能夠使用 Instant 取代 Date,LocalDateTime 取代 Calendar, DateTimeFormatter取代Simpledateformatter,官方給出的解釋:simple beautiful strong immutable thread-safe
        
        
       
       
               
    • 1
    • 1
  • 【強制】高並發時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,就不要用鎖;能 鎖區塊。就不要鎖整個方法體。能用對象鎖,就不要用類鎖

  • 【強制】對多個資源、數據庫表、對象同一時候加鎖時,須要保持一致的加鎖順序,否則可能會造 成死鎖

  • 【強制】並發改動同一記錄時。避免更新丟失。要么在應用層加鎖,要么在緩存加鎖,要么在 數據庫層使用樂觀鎖。使用 version 作為更新根據

    說明:假設每次訪問沖突概率小於 20%,推薦使用樂觀鎖。否則使用悲觀鎖。

    樂觀鎖的重試次 數不得小於 3 次。

    • 1
    • 1
  • 【強制】多線程並行處理定時任務時,Timer 執行多個 TimeTask 時,僅僅要當中之中的一個沒有捕獲 拋出的異常,其他任務便會自己主動終止執行。使用 ScheduledExecutorService 則沒有這個問題。

  • 【推薦】使用 CountDownLatch 進行異步轉同步操作,每一個線程退出前必須調用 countDown 方法,線程運行代碼注意 catch 異常,確保 countDown 方法能夠運行,避免主線程無法運行 至 countDown 方法,直到超時才返回結果。

  • 【推薦】避免 Random 實例被多線程使用。盡管共享該實例是線程安全的。但會因競爭同一 seed 導致的性能下降

    說明:Random 實例包含 java.util.Random 的實例或者 Math.random()實例。 正例:在 JDK7 之后,能夠直接使用 API ThreadLocalRandom,在 JDK7 之前,能夠做到每一個 線程一個實例。

    • 1
    • 2
    • 3
    • 1
    • 2
    • 3
  • 【推薦】通過雙重檢查鎖(double-checked locking)(在並發場景)實現延遲初始化的優 化問題隱患(可參考 The “Double-Checked Locking is Broken” Declaration),推薦問題 解決方式中較為簡單一種(適用於 JDK5 及以上版本號),將目標屬性聲明為 volatile 型

  • 【參考】volatile 解決多線程內存不可見問題。

    對於一寫多讀。是能夠解決變量同步問題。 可是假設多寫,相同無法解決線程安全問題。假設是 count++操作。使用例如以下類實現

    AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 假設是 JDK8,推 薦使用 LongAdder 對象,比 AtomicLong 性能更好(降低樂觀鎖的重試次數)。

    • 1
    • 2
    • 1
    • 2
  • 【參考】 HashMap 在容量不夠進行 resize 時因為高並發可能出現死鏈。導致 CPU 飆升,在 開發過程中注意規避此風險

  • 【參考】ThreadLocal 無法解決共享對象的更新問題,ThreadLocal 對象建議使用 static 修飾。這個變量是針對一個線程內全部操作共同擁有的,所以設置為靜態變量。全部此類實例共享 此靜態變量 ,也就是說在類第一次被使用時裝載,僅僅分配一塊存儲空間,全部此類的對象(僅僅 要是這個線程內定義的)都能夠操控這個變量。


七、控制語句

  • 【強制】在一個 switch 塊內。每一個 case 要么通過 break/return 等來終止,要么凝視說明程 序將繼續運行到哪一個 case 為止;在一個 switch 塊內,都必須包括一個 default 語句而且 放在最后,即使它什么代碼也沒有

  • 【強制】在 if/else/for/while/do 語句中必須使用大括號。即使僅僅有一行代碼,避免使用 以下的形式:if (condition) statements;

  • 【推薦】推薦盡量少用 else。 if-else 的方式能夠改寫成

    if(condition){ ... return obj; } // 接着寫 else 的業務邏輯代碼; 說明:假設非得使用 if()...else if()...else...方式表達邏輯。【強制】請勿超過 3 層, 超過請使用狀態設計模式。 正例:邏輯上超過 3 層的 if-else 代碼能夠使用衛語句。或者狀態模式來實現
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 【推薦】除經常用法(如 getXxx/isXxx)等外。不要在條件推斷中運行其他復雜的語句。將復 雜邏輯推斷的結果賦值給一個有意義的布爾變量名。以提高可讀性。

    說明:非常多 if 語句內的邏輯相當復雜,閱讀者須要分析條件表達式的終於結果,才干明白什么 樣的條件運行什么樣的語句。那么,假設閱讀者分析邏輯表達式錯誤呢? 正例: //偽代碼例如以下 boolean existed = (file.open(fileName, "w") != null) && (...) || (...); if (existed) { ... } 反例: if ((file.open(fileName, "w") != null) && (...) || (...)) { ... } 
        
        
       
       
               
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
  • 【推薦】循環體中的語句要考量性能。下面操作盡量移至循環體外處理。如定義對象、變量、 獲取數據庫連接。進行不必要的 try-catch 操作(這個 try-catch 能否夠移至循環體外)

  • 【推薦】接口入參保護,這樣的場景常見的是用於做批量操作的接口。

  • 【參考】方法中須要進行參數校驗的場景

    • 調用頻次低的方法。

    • 運行時間開銷非常大的方法,

    • 參數校驗時間差點兒能夠忽略不計。但假設由於參數錯誤導致

    • 中間運行回退。或者錯誤,那得不償失。

    • 須要極高穩定性和可用性的方法。

    • 對外提供的開放接口。無論是 RPC/API/HTTP 接口

    • 敏感權限入口

  • 【參考】方法中不須要參數校驗的場景

    • 極有可能被循環調用的方法,不建議對參數進行校驗。但在方法說明里必須注明外部參 數檢查。

    • 底層的方法調用頻度都比較高。一般不校驗。

      畢竟是像純凈水過濾的最后一道,參數錯 誤不太可能究竟層才會暴露問題。一般 DAO 層與 Service 層都在同一個應用中,部署在同一 台server中,所以 DAO 的參數校驗。能夠省略。

    • 被聲明成 private 僅僅會被自己代碼所調用的方法,假設可以確定調用方法的代碼傳入參 數已經做過檢查或者肯定不會有問題。此時可以不校驗參數


八、凝視規約

  • 【強制】類、類屬性、類方法的凝視必須使用 Javadoc 規范,使用/* 內容 /格式,不得使用 //xxx 方式

    說明:在 IDE 編輯窗體中。Javadoc 方式會提示相關凝視。生成 Javadoc 能夠正確輸出對應注 釋;在 IDE 中,project調用方法時。不進入方法就可以懸浮提示方法、參數、返回值的意義,提高 閱讀效率
        
        
       
       
               
    • 1
    • 1
  • 【強制】全部的抽象方法(包含接口中的方法)必需要用 Javadoc 凝視、除了返回值、參數、 異常說明外,還必須指出該方法做什么事情。實現什么功能。

    說明:對子類的實現要求,或者調用注意事項,請一並說明。 
        
        
       
       
               
    • 1
    • 1
  • 【強制】全部的類都必須加入創建者信息。

  • 【強制】方法內部單行凝視,在被凝視語句上方另起一行。使用//凝視。方法內部多行凝視 使用/* */凝視。注意與代碼對齊。

  • 【強制】全部的枚舉類型字段必需要有凝視,說明每一個數據項的用途

  • 【推薦】與其“半吊子”英文來凝視,不如用中文凝視把問題說清楚。專有名詞與keyword保持 英文原文就可以。

    反例:“TCP 連接超時”解釋成“傳輸控制協議連接超時”,理解反而費腦筋。

    • 1
    • 1
  • 【推薦】代碼改動的同一時候,凝視也要進行對應的改動。尤其是參數、返回值、異常、核心邏輯 等的改動。

    說明:代碼與凝視更新不同步,就像路網與導航軟件更新不同步一樣,假設導航軟件嚴重滯后, 就失去了導航的意義。

    • 1
    • 1
  • 【參考】凝視掉的代碼盡量要配合說明。而不是簡單的凝視掉

    說明:代碼被凝視掉有兩種可能性:1)興許會恢復此段代碼邏輯。2)永久不用。前者假設沒 有備注信息,難以知曉凝視動機。后者建議直接刪掉(代碼倉庫保存了歷史代碼)。

    • 1
    • 1
  • 【參考】對於凝視的要求:第一、可以准確反應設計思想和代碼邏輯。第二、可以描寫敘述業務含 義。使別的程序猿可以迅速了解到代碼背后的信息。全然沒有凝視的大段代碼對於閱讀者形同
    天書,凝視是給自己看的,即使隔非常長時間,也能清晰理解當時的思路;凝視也是給繼任者看 的。使其可以高速接替自己的工作。

  • 【參考】好的命名、代碼結構是自解釋的,凝視力求精簡准確、表達到位。避免出現凝視的 一個極端:過多過濫的凝視,代碼的邏輯一旦改動。改動凝視是相當大的負擔。

  • 【參考】特殊凝視標記,請注明標記人與標記時間。注意及時處理這些標記,通過標記掃描。 常常清理此類標記。

    線上故障有時候就是來源於這些標記處的代碼。

    • 待辦事宜(TODO):( 標記人,標記時間。[估計處理時間]) 表示須要實現,但眼下還未實現的功能。這實際上是一個 Javadoc 的標簽。眼下的 Javadoc 還沒有實現,但已經被廣泛使用。僅僅能應用於類,接口和方法(由於它是一個 Javadoc 標簽)。

    • 錯誤,不能工作(FIXME):(標記人,標記時間,[估計處理時間]) 在凝視中用 FIXME 標記某代碼是錯誤的,並且不能工作,須要及時糾正的情況


九、其它

  • 【強制】在使用正則表達式時,利用好其預編譯功能。能夠有效加快正則匹配速度

    說明:不要在方法體內定義:Pattern pattern = Pattern.compile(規則); 
        
        
       
       
               
    • 1
    • 1
  • 【強制】velocity 調用 POJO 類的屬性時,建議直接使用屬性名取值就可以,模板引擎會自己主動按 規范調用 POJO 的 getXxx(),假設是 boolean 基本數據類型變量(boolean 命名不須要加 is 前綴),會自己主動調用 isXxx()方法

    說明:注意假設是 Boolean 包裝類對象。優先調用 getXxx()的方法
        
        
       
       
               
    • 1
    • 1
  • 【強制】后台輸送給頁面的變量必須加$!{var}——中間的感嘆號

    說明:假設 var=null 或者不存在。那么${var}會直接顯示在頁面上
        
        
       
       
               
    • 1
    • 1
  • 【強制】注意 Math.random() 這種方法返回是 double 類型,注意取值的范圍 0≤x<1(可以 取到零值,注意除零異常),假設想獲取整數類型的隨機數,不要將 x 放大 10 的若干倍然后 取整,直接使用 Random 對象的 nextInt 或者 nextLong 方法

  • 【強制】獲取當前毫秒數 System.currentTimeMillis(); 而不是 new Date().getTime();

    說明:假設想獲取更加精確的納秒級時間值。用 System.nanoTime()。在 JDK8 中,針對統計 時間等場景,推薦使用 Instant 類。
  • 【推薦】盡量不要在 vm 中增加變量聲明、邏輯運算符,更不要在 vm 模板中增加不論什么復雜的邏 輯。

  • 【推薦】不論什么數據結構的構造或初始化。都應指定大小。避免數據結構無限增長吃光內存

  • 【推薦】對於“明白停止使用的代碼和配置”。如方法、變量、類、配置文件、動態配置屬性 等要堅決從程序中清理出去,避免造成過多垃圾。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM