1. 程式人生 > >阿里巴巴Java開發手冊個人整理精簡版(一)

阿里巴巴Java開發手冊個人整理精簡版(一)

個人程式設計時日雖說不短,但整體專案經驗感覺上還是比較欠缺,而且個人的程式設計風格並未形成,為了使自己的程式設計更加讓人賞心悅目(而不是傷心)最近看了阿里的Java開發程式設計的規約希望對自己的程式設計風格有些正面的影響,下面是我的一些筆記和總結:
一、程式設計規約
(一) 命名規約
1. 【強制】所有程式設計相關命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。 反例: _name / __name / Object/name/name / Object$
2. 【強制】所有程式設計相關的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。
說明:正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式也要避免採用。 反例: DaZhePromotion [打折] / getPingfenByName() [評分] / int 變數 = 3;
正例: ali / alibaba / taobao / cainiao / aliyun / youku / hangzhou 等國際通用的名稱,可視為英文。
3. 【強制】類名使用UpperCamelCase風格,必須遵從駝峰形式,但以下情形例外:(領域模型的相關命名)DO / DTO / VO / DAO等。 正例:MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion 反例:macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
4. 【強制】方法名、引數名、成員變數、區域性變數都統一使用lowerCamelCase風格,必須遵從駝峰形式。 正例: localValue / getHttpMessage() / inputUserId
5. 【強制】常量命名全部大寫,單詞間用下劃線隔開,力求語義表達完整清楚,不要嫌名字長。 正例: MAX_STOCK_COUNT 反例: MAX_COUNT
6. 【強制】抽象類命名使用Abstract或Base開頭;異常類命名使用Exception結尾;測試類命名以它要測試的類的名稱開始,以Test結尾。
7. 【強制】中括號是陣列型別的一部分,陣列定義如下:String[] args; 反例:請勿使用String args[]的方式來定義
8. 【強制】POJO類中的任何布林型別的變數,都不要加is,否則部分框架解析會引起序列化錯誤。 反例:定義為基本資料型別boolean isSuccess;的屬性,它的方法也是isSuccess(),RPC框架在反向解析的時候,“以為”對應的屬性名稱是success,導致屬性獲取不到,進而丟擲異常。
9. 【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用單數形式,但是類名如果有複數含義,類名可以使用複數形式。 正例: 應用工具類包名為com.alibaba.mpp.util、類名為MessageUtils(此規則參考spring的框架結構)
10.【強制】杜絕完全不規範的縮寫,避免望文不知義。 反例:<某業務程式碼>AbstractClass“縮寫”命名成AbsClass;condition“縮寫”命名成 condi,此類隨意縮寫嚴重降低了程式碼的可閱讀性。
11.【推薦】如果使用到了設計模式,建議在類名中體現出具體模式。 說明:將設計模式體現在名字中,有利於閱讀者快速理解架構設計思想。
正例:public class OrderFactory; public class LoginProxy; public class ResourceObserver;
12.【推薦】介面類中的方法和屬性不要加任何修飾符號(public 也不要加),保持程式碼的簡潔性,並加上有效的javadoc註釋。儘量不要在接口裡定義變數,如果一定要定義變數,肯定是與介面方法相關,並且是整個應用的基礎常量。
正例:
介面方法簽名:void f();
介面基礎常量表示:String COMPANY = “alibaba”;
反例:
介面方法定義:public abstract void f();
說明:JDK8中介面允許有預設實現,那麼這個default方法,是對所有實現類都有價值的預設實現。
13.介面和實現類的命名有兩套規則:
1)【強制】對於Service和DAO類,基於SOA的理念,暴露出來的服務一定是介面,內部的實現類用Impl的字尾與介面區別。
正例:CacheServiceImpl實現CacheService介面。
2)【推薦】 如果是形容能力的介面名稱,取對應的形容詞做介面名(通常是–able的形式)。
正例:AbstractTranslator實現 Translatable。
14.【參考】列舉類名建議帶上Enum字尾,列舉成員名稱需要全大寫,單詞間用下劃線隔開。
說明:列舉其實就是特殊的常量類,且構造方法被預設強制是私有。
正例:列舉名字:DealStatusEnum;成員名稱:SUCCESS / UNKOWN_REASON。
15.【參考】各層命名規約:
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。
(二) 常量定義
1. 【強制】不允許出現任何魔法值(即未經定義的常量)直接出現在程式碼中。
反例:
String key=”Id#taobao_”+tradeId;
cache.put(key, value);
2. 【強制】long或者Long初始賦值時,必須使用大寫的L,不能是小寫的l,小寫容易跟數字1混淆,造成誤解。
說明:Long a = 2l; 寫的是數字的21,還是Long型的2?
3. 【推薦】不要使用一個常量類維護所有常量,應該按常量功能進行歸類,分開維護。如:快取相關的常量放在類:CacheConsts下;系統配置相關的常量放在類:ConfigConsts下。
說明:大而全的常量類,非得ctrl+f才定位到修改的常量,不利於理解,也不利於維護。
4. 【推薦】常量的複用層次有五層:跨應用共享常量、應用內共享常量、子工程內共享常量、包內共享常量、類內共享常量。
1) 跨應用共享常量:放置在二方庫中,通常是client.jar中的const目錄下。
2) 應用內共享常量:放置在一方庫的modules中的const目錄下。 反例:易懂變數也要統一定義成應用內共享常量,兩位攻城師在兩個類中分別定義了表示“是”的變數: 類A中:public static final String YES = “yes”; 類B中:public static final String YES = “y”; A.YES.equals(B.YES),預期是true,但實際返回為false,導致產生線上問題。
3) 子工程內部共享常量:即在當前子工程的const目錄下。
4) 包內共享常量:即在當前包下單獨的const目錄下。
5) 類內共享常量:直接在類內部private static final定義。
5. 【推薦】如果變數值僅在一個範圍內變化用Enum類。如果還帶有名稱之外的延伸屬性,必須使用Enum類,下面正例中的數字就是延伸資訊,表示星期幾。 正例:public Enum{ MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7);}
(三) 格式規約
1. 【強制】大括號的使用約定。如果是大括號內為空,則簡潔地寫成{}即可,不需要換行;如果是非空程式碼塊則:
1) 左大括號前不換行。
2) 左大括號後換行。
3) 右大括號前換行。
4) 右大括號後還有else等程式碼則不換行;表示終止右大括號後必須換行。
2. 【強制】 左括號和後一個字元之間不出現空格;同樣,右括號和前一個字元之間也不出現空格。詳見第5條下方正例提示。
3. 【強制】if/for/while/switch/do等保留字與左右括號之間都必須加空格。
4. 【強制】任何運算子左右必須加一個空格。
說明:運算子包括賦值運算子=、邏輯運算子&&、加減乘除符號、三目執行符等。
5. 【強制】程式碼塊縮排4個空格,如果使用tab縮排,請設定成1個tab為4個空格。 正例: (涉及1-5點)

public static void main(String args[]) { 
    // 縮排4個空格 
    String say = "hello"; 
    // 運算子的左右必須有一個空格 
    int flag = 0; 
    // 關鍵詞if與括號之間必須有一個空格,括號內f與左括號,1與右括號不需要空格 
    if (flag == 0) { 
    System.out.println(say); 
    }
    // 左大括號前加空格且不換行;左大括號後換
    if (flag == 1) { 
    System.out.println("world"
); // 右大括號前換行,右大括號後有else,不用換行 } else { System.out.println("ok"); //右大括號作為結束必須換行 } }
  1. 【強制】單行字元數限制不超過120個,超出需要換行,換行時,遵循如下原則:
    1) 換行時相對上一行縮排4個空格。
    2) 運算子與下文一起換行。
    3) 方法呼叫的點符號與下文一起換行。
    4) 在多個引數超長,逗號後進行換行。
    5) 在括號前不要換行,見反例。
    正例:
StringBuffer sb = new StringBuffer(); 
//超過120個字元的情況下,換行縮排4個空格,並且方法前的點符號一起換行
sb.append("zi").append("xin")… .append("huang");

反例:

StringBuffer sb = new StringBuffer(); 
//超過120個字元的情況下,不要在括號前換行 
sb.append("zi").append("xin")…append 
("huang"); 
//引數很多的方法呼叫也超過120個字元,逗號後才是換行處 
method(args1, args2, args3, ... 
, argsX);
  1. 【強制】方法引數在定義和傳入時,多個引數逗號後邊必須加空格。 正例:下例中實參的”a”,後邊必須要有一個空格。 method(“a”, “b”, “c”);
  2. 【推薦】沒有必要增加若干空格來使某一行的字元與上一行的相應字元對齊。
    正例:
    int a = 3;
    long b = 4L;
    float c = 5F;
    StringBuffer sb = new StringBuffer();
    說明:增加sb這個變數,如果需要對齊,則給a、b、c都要增加幾個空格,在變數比較多的情況下,是一種累贅的事情。
  3. 【強制】IDE的text file encoding設定為UTF-8; IDE中檔案的換行符使用Unix格式,不要使用windows格式。
    10.【推薦】方法體內的執行語句組、變數的定義語句組、不同的業務邏輯之間或者不同的語義之間插入一個空行。相同業務邏輯和語義之間不需要插入空行。
    說明:沒有必要插入多行空格進行隔開。
    (四) OOP規約
  4. 【強制】避免通過一個類的物件引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成本,直接用類名來訪問即可。
  5. 【強制】所有的覆寫方法,必須加@Override註解。 反例:getObject()與get0bject()的問題。一個是字母的O,一個是數字的0,加@Override可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編譯報錯。
  6. 【強制】相同引數型別,相同業務含義,才可以使用Java的可變引數,避免使用Object。 說明:可變引數必須放置在引數列表的最後。(提倡同學們儘量不用可變引數程式設計) 正例:public User getUsers(String type, Integer… ids);
  7. 【強制】對外暴露的介面簽名,原則上不允許修改方法簽名,避免對介面呼叫方產生影響。介面過時必須加@Deprecated註解,並清晰地說明採用的新介面或者新服務是什麼。
  8. 【強制】不能使用過時的類或方法。 說明:java.net.URLDecoder 中的方法decode(String encodeStr) 這個方法已經過時,應該使用雙引數decode(String source, String encode)。介面提供方既然明確是過時介面,那麼有義務同時提供新的介面;作為呼叫方來說,有義務去考證過時方法的新實現是什麼。
  9. 【強制】Object的equals方法容易拋空指標異常,應使用常量或確定有值的物件來呼叫equals。
    正例:
    “test”.equals(object);
    反例:
    object.equals(“test”);
    說明:推薦使用java.util.Objects#equals (JDK7引入的工具類)
  10. 【強制】所有的相同型別的包裝類物件之間值的比較,全部使用equals方法比較。 說明:對於Integer var=?在-128至127之間的賦值,Integer物件是在IntegerCache.cache產生,會複用已有物件,這個區間內的Integer值可以直接使用==進行判斷,但是這個區間之外的所有資料,都會在堆上產生,並不會複用已有物件,這是一個大坑,推薦使用equals方法進行判斷。
  11. 【強制】關於基本資料型別與包裝資料型別的使用標準如下:
    1) 所有的POJO類屬性必須使用包裝資料型別。
    2) RPC方法的返回值和引數必須使用包裝資料型別。
    3) 所有的區域性變數推薦使用基本資料型別。
    說明:POJO類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何NPE問題,或者入庫檢查,都由使用者來保證。
    正例:資料庫的查詢結果可能是null,因為自動拆箱,用基本資料型別接收有NPE風險。
    反例:某業務的交易報表上顯示成交總額漲跌情況,即正負x%,x為基本資料型別,呼叫的RPC服務,呼叫不成功時,返回的是預設值,頁面顯示:0%,這是不合理的,應該顯示成中劃線-。所以包裝資料型別的null值,能夠表示額外的資訊,如:遠端呼叫失敗,異常退出。
  12. 【強制】定義DO/DTO/VO等POJO類時,不要設定任何屬性預設值。
    反例:某業務的DO的gmtCreate預設值為new Date();但是這個屬性在資料提取時並沒有置入具體值,在更新其它欄位時又附帶更新了此欄位,導致建立時間被修改成當前時間。
    10.【強制】序列化類新增屬性時,請不要修改serialVersionUID欄位,避免反序列失敗;如果完全不相容升級,避免反序列化混亂,那麼請修改serialVersionUID值。 說明:注意serialVersionUID不一致會丟擲序列化執行時異常。
    11.【強制】構造方法裡面禁止加入任何業務邏輯,如果有初始化邏輯,請放在init方法中。 12.【強制】POJO類必須寫toString方法。使用工具類source> generate toString時,如果繼承了另一個POJO類,注意在前面加一下super.toString。 說明:在方法執行丟擲異常時,可以直接呼叫POJO的toString()方法列印其屬性值,便於排查問題。
  13. 【推薦】使用索引訪問用String的split方法得到的陣列時,需做最後一個分隔符後有無內容的檢查,否則會有拋IndexOutOfBoundsException的風險。
    說明:
    String str = “a,b,c,,”;
    String[] ary = str.split(“,”);
    //預期大於3,結果是3
    System.out.println(ary.length);
    14.【推薦】當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序放置在一起,便於閱讀。
    15.【推薦】 類內方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter/setter方法。
    說明:公有方法是類的呼叫者和維護者最關心的方法,首屏展示最好;保護方法雖然只是子類關心,也可能是“模板設計模式”下的核心方法;而私有方法外部一般不需要特別關心,是一個黑盒實現;因為方法資訊價值較低,所有Service和DAO的getter/setter方法放在類體最後。
  14. 【推薦】setter方法中,引數名稱與類成員變數名稱一致,this.成員名=引數名。在getter/setter方法中,儘量不要增加業務邏輯,增加排查問題難度。
    反例:
public Integer getData(){
 if(true) {
      return data + 100;
   } else {
        return data - 100;
      } 
  }
  1. 【推薦】迴圈體內,字串的聯接方式,使用StringBuilder的append方法進行擴充套件。
    說明:反編譯出的位元組碼檔案顯示每次迴圈都會new出一個StringBuilder物件,然後進行append操作,最後通過toString方法返回String物件,造成記憶體資源浪費。
    18.【推薦】final可提高程式響應效率,宣告成final的情況:
    1) 不需要重新賦值的變數,包括類屬性、區域性變數。
    2) 物件引數前加final,表示不允許修改引用的指向。
    3) 類方法確定不允許被重寫。
    19.【推薦】慎用Object的clone方法來拷貝物件。
    說明:物件的clone方法預設是淺拷貝,若想實現深拷貝需要重寫clone方法實現屬性物件的拷貝。
    20.【推薦】類成員與方法訪問控制從嚴:
    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的成員變數,刪除一下,不得手心冒點汗嗎?變數像自己的小孩,儘量在自己的視線內,變數作用域太大,如果無限制的到處跑,那麼你會擔心的。
    未完待續。。。。