1. 程式人生 > >阿里程式碼風格

阿里程式碼風格

 

Table of Contents

前言

目錄

一、程式設計規約

(一) 命名風格

(二) 常量定義

(三) 程式碼格式

(四) OOP規約

(五) 集合處理

(六) 併發處理

(七) 控制語句

(八) 註釋規約

二、異常日誌

(一) 異常處理

(二) 日誌規約

(九) 其它

三、單元測試

四、安全規約

五、MySQL資料庫

(一) 建表規約

(二) 索引規約

(三) SQL語句

(四) ORM對映

六、工程結構

(一) 應用分層

(二) 二方庫依賴

(三) 伺服器

附1:版本歷史

附2:本手冊專有名詞

 

前言

《阿里巴巴 Java 開發手冊》是阿里巴巴集團技術團隊的集體智慧結晶和經驗總

結,經歷了多次大規模一線實戰的檢驗及不斷的完善,系統化地整理成冊,回饋給廣

大開發者。現代軟體行業的高速發展對開發者的綜合素質要求越來越高,因為不僅是

程式設計知識點,其它維度的知識點也會影響到軟體的最終交付質量。比如:資料庫的表

結構和索引設計缺陷可能帶來軟體上的架構缺陷或效能風險;工程結構混亂導致後續

維護艱難;沒有鑑權的漏洞程式碼易被黑客攻擊等等。所以本手冊以 Java 開發者為中心

視角,劃分為程式設計規約、異常日誌、單元測試、安全規約、工程結構、MySQL 資料庫六

個維度,再根據內容特徵,細分成若干二級子目錄。根據約束力強弱及故障敏感性,

規約依次分為強制、推薦、參考三大類。對於規約條目的延伸資訊中,“說明”對內

容做了適當擴充套件和解釋;“正例”提倡什麼樣的編碼和實現方式;“反例”說明需要

提防的雷區,以及真實的錯誤案例。

本手冊的願景是碼出高效,碼出質量。現代軟體架構都需要協同開發完成,高效

協作即降低協同成本,提升溝通效率,所謂無規矩不成方圓,無規範不能協作。眾所

周知,制訂交通法規表面上是要限制行車權,實際上是保障公眾的人身安全。試想如

果沒有限速,沒有紅綠燈,誰還敢上路行駛。對軟體來說,適當的規範和標準絕不是

消滅程式碼內容的創造性、優雅性,而是限制過度個性化,以一種普遍認可的統一方式

一起做事,提升協作效率。程式碼的字裡行間流淌的是軟體生命中的血液,質量的提升

是儘可能少踩坑,杜絕踩重複的坑,切實提升質量意識。

考慮到可以零距離地與眾多開發同學進行互動,決定未來線上維護《手冊》內容,

此 1.3.1 的 PDF 版本,是對外釋放的最終紀念版,銘記釋出第一版以來的 358 天旅程;

我們已經在杭州雲棲大會上進行了阿里巴巴 Java 開發規約外掛點此下載,阿里雲效

(一

站式企業協同研發雲)也集成了程式碼規約掃描引擎。最後,《碼出高效——阿里巴巴

Java 開發手冊詳解》即將出版,敬請關注。

 

 

目錄

前言

一、程式設計規約 ......................................................................... 1

(一) 命名風格 ................................................................... 1

(二) 常量定義 ................................................................... 3

(三) 程式碼格式 ................................................................... 4

(四) OOP 規約 ................................................................... 6

(五) 集合處理 ................................................................... 9

(六) 併發處理 .................................................................. 12

(七) 控制語句 .................................................................. 14

(八) 註釋規約 .................................................................. 16

(九) 其它 ...................................................................... 17

二、異常日誌 ........................................................................ 17

(一) 異常處理 .................................................................. 17

(二) 日誌規約 .................................................................. 19

三、單元測試 ........................................................................ 22

四、安全規約 ........................................................................ 24

五、MySQL 資料庫 .................................................................... 25

(一) 建表規約 .................................................................. 25

(二) 索引規約 .................................................................. 26

(三) SQL 語句 .................................................................. 28

(四) ORM 對映 .................................................................. 29

六、工程結構 ........................................................................ 31

(一) 應用分層 .................................................................. 31

(二) 二方庫依賴 ................................................................ 32

(三) 伺服器 .................................................................... 33

附 1:版本歷史 ....................................................................... 35

附 2:本手冊專有名詞 ................................................................. 36

 

 

(注:瀏覽時請使用 PDF 左側導航欄)

 

 

 

 

阿里巴巴 Java 開發手冊

Java 開發手冊

版本號

制定團隊

更新日期

備註

1.3.1

阿里巴巴集團技術團隊

2017.11.30

修正部分描述(紀念版)

 

一、程式設計規約

(一) 命名風格

1. 【強制】程式碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。

反例:_name / __name / $name / name_ / name$ / name__

2. 【強制】程式碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。

說明:正確的英文拼寫和語法可以讓閱讀者易於理解,避免歧義。注意,即使純拼音命名方式

也要避免採用。

正例:alibaba / taobao / youku / hangzhou 等國際通用的名稱,可視同英文。

反例:DaZhePromotion [打折] / getPingfenByName() [評分] / int 某變數 = 3

3. 【強制】類名使用 UpperCamelCase 風格,但以下情形例外:DO / BO / DTO / VO / AO /

PO 等。

正例: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. 【強制】型別與中括號緊挨相連來定義陣列。

正例:定義整形陣列 int[] arrayDemo;

反例:在 main 引數中,使用 String args[]來定義。

8. 【強制】POJO 類中布林型別的變數,都不要加 is 字首,否則部分框架解析會引起序列化錯誤。

反例:定義為基本資料型別 Boolean isDeleted;的屬性,它的方法也是 isDeleted(),RPC

1/36

阿里巴巴 Java 開發手冊

框架在反向解析的時候,“誤以為”對應的屬性名稱是 deleted,導致屬性獲取不到,進而拋

出異常。

9. 【強制】包名統一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞。包名統一使用

單數形式,但是類名如果有複數含義,類名可以使用複數形式。

正例:應用工具類包名為 com.alibaba.ai.util、類名為 MessageUtils(此規則參考 spring 的框架結構)

10. 【強制】杜絕完全不規範的縮寫,避免望文不知義。

反例:AbstractClass“縮寫”命名成 AbsClass;condition“縮寫”命名成 condi,此類隨

意縮寫嚴重降低了程式碼的可閱讀性。

11. 【推薦】為了達到程式碼自解釋的目標,任何自定義程式設計元素在命名時,使用盡量完整的單詞

組合來表達其意。

正例:從遠端倉庫拉取程式碼的類命名為 PullCodeFromRemoteRepository。

反例:變數 int a; 的隨意命名方式。

12. 【推薦】如果模組、介面、類、方法使用了設計模式,在命名時體現出具體模式。

說明:將設計模式體現在名字中,有利於閱讀者快速理解架構設計理念。

正例:public class OrderFactory;

public class LoginProxy;

public class ResourceObserver;

13. 【推薦】介面類中的方法和屬性不要加任何修飾符號(public 也不要加),保持程式碼的簡潔

性,並加上有效的 Javadoc 註釋。儘量不要在接口裡定義變數,如果一定要定義變數,肯定是

與介面方法相關,並且是整個應用的基礎常量。

正例:介面方法簽名 void f();

介面基礎常量 String COMPANY = "alibaba";

反例:介面方法定義 public abstract void f();

說明:JDK8 中介面允許有預設實現,那麼這個 default 方法,是對所有實現類都有價值的默

認實現。

14. 介面和實現類的命名有兩套規則:

1)【強制】對於 Service 和 DAO 類,基於 SOA 的理念,暴露出來的服務一定是介面,內部

的實現類用 Impl 的字尾與介面區別。

正例:CacheServiceImpl 實現 CacheService 介面。

2) 【推薦】 如果是形容能力的介面名稱,取對應的形容詞為介面名(通常是–able 的形式)。

正例:AbstractTranslator 實現 Translatable。

2/36

阿里巴巴 Java 開發手冊

15. 【參考】列舉類名建議帶上 Enum 字尾,列舉成員名稱需要全大寫,單詞間用下劃線隔開。

說明:列舉其實就是特殊的常量類,且構造方法被預設強制是私有。

正例:列舉名字為 ProcessStatusEnum 的成員名稱:SUCCESS / UNKNOWN_REASON。

16. 【參考】各層命名規約:

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 下。

4. 【推薦】常量的複用層次有五層:跨應用共享常量、應用內共享常量、子工程內共享常量、包

內共享常量、類內共享常量。

1) 跨應用共享常量:放置在二方庫中,通常是 client.jar 中的 constant 目錄下。

2) 應用內共享常量:放置在一方庫中,通常是子模組中的 constant 目錄下。

反例:易懂變數也要統一定義成應用內共享常量,兩位攻城師在兩個類中分別定義了表示

“是”的變數:

類 A 中:public static final String YES = "yes";

3/36

阿里巴巴 Java 開發手冊

類 B 中:public static final String YES = "y";

A.YES.equals(B.YES),預期是 true,但實際返回為 false,導致線上問題。

3) 子工程內部共享常量:即在當前子工程的 constant 目錄下。

4) 包內共享常量:即在當前包下單獨的 constant 目錄下。

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

5. 【推薦】如果變數值僅在一個固定範圍內變化用 enum 型別來定義。

說明:如果存在名稱之外的延伸屬性使用 enum 型別,下面正例中的數字就是延伸資訊,表示

一年中的第幾個季節。

正例:

public enum SeasonEnum {

SPRING(1), SUMMER(2), AUTUMN(3), WINTER(4);

int seq;

SeasonEnum(int seq){

this.seq = seq;

}

}

 

(三) 程式碼格式

1. 【強制】大括號的使用約定。如果是大括號內為空,則簡潔地寫成{}即可,不需要換行;如果

是非空程式碼塊則:

1) 左大括號前不換行。

2) 左大括號後換行。

3) 右大括號前換行。

4) 右大括號後還有 else 等程式碼則不換行;表示終止的右大括號後必須換行。

2. 【強制】 左小括號和字元之間不出現空格;同樣,右小括號和字元之間也不出現空格。詳見

第 5 條下方正例提示。

反例:if (空格 a == b 空格)

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

4. 【強制】任何二目、三目運算子的左右兩邊都需要加一個空格。

說明:運算子包括賦值運算子=、邏輯運算子&&、加減乘除符號等。

5. 【強制】採用 4 個空格縮排,禁止使用 tab 字元。

說明:如果使用 tab 縮排,必須設定 1 個 tab 為 4 個空格。IDEA 設定 tab 為 4 個空格時,

請勿勾選 Use tab character;而在 eclipse 中,必須勾選 insert spaces for tabs。

正例: (涉及 1-5 點)

public static void main(String[] args) {

// 縮排 4 個空格

4/36

阿里巴巴 Java 開發手冊

String say = "hello";

// 運算子的左右必須有一個空格

int flag = 0;

// 關鍵詞 if 與括號之間必須有一個空格,括號內的 f 與左括號,0 與右括號不需要空格

if (flag == 0) {

System.out.println(say);

}

 

// 左大括號前加空格且不換行;左大括號後換行

if (flag == 1) {

System.out.println("world");

// 右大括號前換行,右大括號後有 else,不用換行

} else {

System.out.println("ok");

// 在右大括號後直接結束,則必須換行

}

}

6. 【強制】註釋的雙斜線與註釋內容之間有且僅有一個空格。

正例:

 

// 這是示例註釋,請注意在雙斜線之後有一個空格

 

String ygb = new String();

7. 【強制】單行字元數限制不超過 120 個,超出需要換行,換行時遵循如下原則:

1) 第二行相對第一行縮排 4 個空格,從第三行開始,不再繼續縮排,參考示例。

2) 運算子與下文一起換行。

3) 方法呼叫的點符號與下文一起換行。

4) 方法呼叫時,多個引數,需要換行時,在逗號後進行。

5) 在括號前不要換行,見反例。

正例:

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);

8. 【強制】方法引數在定義和傳入時,多個引數逗號後邊必須加空格。

正例:下例中實參的"a",後邊必須要有一個空格。

method("a", "b", "c");

5/36

阿里巴巴 Java 開發手冊

9. 【強制】IDE 的 text file encoding 設定為 UTF-8; IDE 中檔案的換行符使用 Unix 格式,

不要使用 Windows 格式。

10. 【推薦】沒有必要增加若干空格來使某一行的字元與上一行對應位置的字元對齊。

正例:

int a = 3;

long b = 4L;

float c = 5F;

StringBuffer sb = new StringBuffer();

說明:增加 sb 這個變數,如果需要對齊,則給 a、b、c 都要增加幾個空格,在變數比較多的

情況下,是非常累贅的事情。

11. 【推薦】不同邏輯、不同語義、不同業務的程式碼之間插入一個空行分隔開來以提升可讀性。

說明:沒有必要插入多個空行進行隔開。

(四) OOP 規約

1. 【強制】避免通過一個類的物件引用訪問此類的靜態變數或靜態方法,無謂增加編譯器解析成

本,直接用類名來訪問即可。

2. 【強制】所有的覆寫方法,必須加@Override 註解。

說明:getObject()與 get0bject()的問題。一個是字母的 O,一個是數字的 0,加@Override 可以準確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進行修改,其實現類會馬上編

譯報錯。

3. 【強制】相同引數型別,相同業務含義,才可以使用 Java 的可變引數,避免使用 Object。

說明:可變引數必須放置在引數列表的最後。(提倡同學們儘量不用可變引數程式設計)

正例:public User getUsers(String type, Integer... ids) {...}

4. 【強制】外部正在呼叫或者二方庫依賴的介面,不允許修改方法簽名,避免對介面呼叫方產生

影響。介面過時必須加@Deprecated 註解,並清晰地說明採用的新介面或者新服務是什麼。

5. 【強制】不能使用過時的類或方法。

說明:java.net.URLDecoder 中的方法 decode(String encodeStr) 這個方法已經過時,應

該使用雙引數 decode(String source, String encode)。介面提供方既然明確是過時介面,

那麼有義務同時提供新的介面;作為呼叫方來說,有義務去考證過時方法的新實現是什麼。

6. 【強制】Object 的 equals 方法容易拋空指標異常,應使用常量或確定有值的物件來呼叫

equals。

正例:"test".equals(object);

反例:object.equals("test");

說明:推薦使用 java.util.Objects#equals(JDK7 引入的工具類)

6/36

阿里巴巴 Java 開發手冊

7. 【強制】所有的相同型別的包裝類物件之間值的比較,全部使用 equals 方法比較。

說明:對於 Integer var = ? 在-128 至 127 範圍內的賦值,Integer 物件是在

IntegerCache.cache 產生,會複用已有物件,這個區間內的 Integer 值可以直接使用==進行

判斷,但是這個區間之外的所有資料,都會在堆上產生,並不會複用已有物件,這是一個大坑,

推薦使用 equals 方法進行判斷。

8. 關於基本資料型別與包裝資料型別的使用標準如下:

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

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

3) 【推薦】所有的區域性變數使用基本資料型別。

說明:POJO 類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進行賦值,任何

NPE 問題,或者入庫檢查,都由使用者來保證。

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

反例:比如顯示成交總額漲跌情況,即正負 x%,x 為基本資料型別,呼叫的 RPC 服務,呼叫

不成功時,返回的是預設值,頁面顯示為 0%,這是不合理的,應該顯示成中劃線。所以包裝

資料型別的 null 值,能夠表示額外的資訊,如:遠端呼叫失敗,異常退出。

9. 【強制】定義 DO/DTO/VO 等 POJO 類時,不要設定任何屬性預設值。

反例:POJO 類的 gmtCreate 預設值為 new Date();但是這個屬性在資料提取時並沒有置入具

體值,在更新其它欄位時又附帶更新了此欄位,導致建立時間被修改成當前時間。

10. 【強制】序列化類新增屬性時,請不要修改 serialVersionUID 欄位,避免反序列失敗;如

果完全不相容升級,避免反序列化混亂,那麼請修改 serialVersionUID 值。

說明:注意 serialVersionUID 不一致會丟擲序列化執行時異常。

11. 【強制】構造方法裡面禁止加入任何業務邏輯,如果有初始化邏輯,請放在 init 方法中。

12. 【強制】POJO 類必須寫 toString 方法。使用 IDE 中的工具: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 條規則。

7/36

阿里巴巴 Java 開發手冊

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

說明:公有方法是類的呼叫者和維護者最關心的方法,首屏展示最好;保護方法雖然只是子類

關心,也可能是“模板設計模式”下的核心方法;而私有方法外部一般不需要特別關心,是一個

黑盒實現;因為承載的資訊價值較低,所有 Service 和 DAO 的 getter/setter 方法放在類體

最後。

16. 【推薦】setter 方法中,引數名稱與類成員變數名稱一致,this.成員名 = 引數名。在

getter/setter 方法中,不要增加業務邏輯,增加排查問題的難度。

反例:

public Integer getData() {

if (condition) {

return this.data + 100;

} else {

return this.data - 100;

}

}

17. 【推薦】迴圈體內,字串的連線方式,使用 StringBuilder 的 append 方法進行擴充套件。

說明:反編譯出的位元組碼檔案顯示每次迴圈都會 new 出一個 StringBuilder 物件,然後進行

append 操作,最後通過 toString 方法返回 String 物件,造成記憶體資源浪費。

反例:

String str = "start";

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

str = str + "hello";

}

18. 【推薦】final 可以宣告類、成員變數、方法、以及本地變數,下列情況使用 final 關鍵字:

1) 不允許被繼承的類,如:String 類。

2) 不允許修改引用的域物件,如:POJO 類的域變數。

3) 不允許被重寫的方法,如:POJO 類的 setter 方法。

4) 不允許執行過程中重新賦值的區域性變數。

5) 避免上下文重複使用一個變數,使用 final 描述可以強制重新定義一個變數,方便更好

地進行重構。

19. 【推薦】慎用 Object 的 clone 方法來拷貝物件。

說明:物件的 clone 方法預設是淺拷貝,若想實現深拷貝需要重寫 clone 方法實現屬性物件

的拷貝。

20. 【推薦】類成員與方法訪問控制從嚴:

1) 如果不允許外部直接通過 new 來建立物件,那麼構造方法必須是 private。

2) 工具類不允許有 public 或 default 構造方法。

3) 類非 static 成員變數並且與子類共享,必須是 protected。

8/36

阿里巴巴 Java 開發手冊

4) 類非 static 成員變數並且僅在本類使用,必須是 private。

5) 類 static 成員變數如果僅在本類使用,必須是 private。

6) 若是 static 成員變數,必須考慮是否為 final。

7) 類成員方法只供類內部呼叫,必須是 private。

8) 類成員方法只對繼承類公開,那麼限制為 protected。

說明:任何類、方法、引數、變數,嚴控訪問範圍。過於寬泛的訪問範圍,不利於模組解耦。

思考:如果是一個 private 的方法,想刪除就刪除,可是一個 public 的 service 成員方法或

成員變數,刪除一下,不得手心冒點汗嗎?變數像自己的小孩,儘量在自己的視線內,變數作

用域太大,無限制的到處跑,那麼你會擔心的。

 

(五) 集合處理

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 帶參方法,入參分配的陣列空間不夠大時,toArray 方法內部將重新分配

記憶體空間,並返回新陣列地址;如果陣列元素個數大於實際所需,下標為[ list.size() ]

的陣列元素將被置為 null,其它陣列元素保持原值,因此最好將方法入引數組大小定義與集

合元素個數一致。

正例:

List<String> list = new ArrayList<String>(2);

list.add("guan");

list.add("bao");

String[] array = new String[list.size()];

array = list.toArray(array);

9/36

阿里巴巴 Java 開發手冊

反例:直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強轉其它

型別陣列將出現 ClassCastException 錯誤。

5. 【強制】使用工具類 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)也會隨之修改。

6. 【強制】泛型萬用字元<? extends T>來接收返回的資料,此寫法的泛型集合不能使用 add 方

法,而<? super T>不能使用 get 方法,作為介面呼叫賦值時易出錯。

說明:擴充套件說一下 PECS(Producer Extends Consumer Super)原則:第一、頻繁往外讀取內

容的,適合用<? extends T>。第二、經常往裡插入的,適合用<? super T>。

7. 【強制】不要在 foreach 迴圈裡進行元素的 remove/add 操作。remove 元素請使用 Iterator 方式,如果併發操作,需要對 Iterator 物件加鎖。

正例:

Iterator<String> iterator = list.iterator();

while (iterator.hasNext()) {

String item = iterator.next();

if (刪除元素的條件) {

iterator.remove();

}

}

反例:

List<String> list = new ArrayList<String>();

list.add("1");

list.add("2");

for (String item : list) {

if ("1".equals(item)) {

list.remove(item);

}

}

說明:以上程式碼的執行結果肯定會出乎大家的意料,那麼試一下把“1”換成“2”,會是同樣的

結果嗎?

8. 【強制】 在 JDK7 版本及以上,Comparator 要滿足如下三個條件,不然 Arrays.sort,

Collections.sort 會報 IllegalArgumentException 異常。

說明:三個條件如下

1) x,y 的比較結果和 y,x 的比較結果相反。

2) x>y,y>z,則 x>z。

10/36

阿里巴巴 Java 開發手冊

3) x=y,則 x,z 比較結果和 y,z 比較結果相同。

反例:下例中沒有處理相等的情況,實際使用中可能會出現異常:

new Comparator<Student>() {

@Override

public int compare(Student o1, Student o2) {

return o1.getId() > o2.getId() ? 1 : -1;

}

};

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

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

正例:

initialCapacity = (需要儲存的元素個數 / 負載因子) + 1。注意負載因子(即 loader

factor)預設為 0.75,如果暫時無法確定初始值大小,請設定為 16(即預設值)。

反例:HashMap 需要放置 1024 個元素,由於沒有設定容量初始大小,隨著元素不斷增加,容

量 7 次被迫擴大,resize 需要重建 hash 表,嚴重影響效能。

10. 【推薦】使用 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 值組合集合。

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

集合類

Key

Value

Super

說明

Hashtable

不允許為 null

不允許為 null

Dictionary

執行緒安全

ConcurrentHashMap

不允許為 null

不允許為 null

AbstractMap

鎖分段技術(JDK8:CAS)

TreeMap

不允許為 null

允許為 null

AbstractMap

執行緒不安全

HashMap

允許為 null

允許為 null

AbstractMap

執行緒不安全

反例: 由於 HashMap 的干擾,很多人認為 ConcurrentHashMap 是可以置入 null 值,而事實上,

儲存 null 值時會丟擲 NPE 異常。

12. 【參考】合理利用好集合的有序性(sort)和穩定性(order),避免集合的無序性(unsort)和

不穩定性(unorder)帶來的負面影響。

說明:有序性是指遍歷的結果是按某種比較規則依次排列的。穩定性指集合每次遍歷的元素次

序是一定的。如:ArrayList 是 order/unsort;HashMap 是 unorder/unsort;TreeSet 是

order/sort。

11/36

阿里巴巴 Java 開發手冊

13. 【參考】利用 Set 元素唯一的特性,可以快速對一個集合進行去重操作,避免使用 List 的

contains 方法進行遍歷、對比、去重操作。

 

(六) 併發處理

1. 【強制】獲取單例物件需要保證執行緒安全,其中的方法也要保證執行緒安全。

說明:資源驅動類、工具類、單例工廠類都需要注意。

2. 【強制】建立執行緒或執行緒池時請指定有意義的執行緒名稱,方便出錯時回溯。

正例:

public class TimerTaskThread extends Thread {

public TimerTaskThread() {

super.setName("TimerTaskThread");

...

}

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

說明:使用執行緒池的好處是減少在建立和銷燬執行緒上所花的時間以及系統資源的開銷,解決資

源不足的問題。如果不使用執行緒池,有可能造成系統建立大量同類執行緒而導致消耗完記憶體或者

“過度切換”的問題。

4. 【強制】執行緒池不允許使用 Executors 去建立,而是通過 ThreadPoolExecutor 的方式,這樣

的處理方式讓寫的同學更加明確執行緒池的執行規則,規避資源耗盡的風險。

說明:Executors 返回的執行緒池物件的弊端如下:

1)FixedThreadPool 和 SingleThreadPool:

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

2)CachedThreadPool 和 ScheduledThreadPool:

允許的建立執行緒數量為 Integer.MAX_VALUE,可能會建立大量的執行緒,從而導致 OOM。

5. 【強制】SimpleDateFormat 是執行緒不安全的類,一般不要定義為 static 變數,如果定義為

static,必須加鎖,或者使用 DateUtils 工具類。

正例:注意執行緒安全,使用 DateUtils。亦推薦如下處理:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {

@Override

protected DateFormat initialValue() {

return new SimpleDateFormat("yyyy-MM-dd");

}

};

說明:如果是 JDK8 的應用,可以使用 Instant 代替 Date,LocalDateTime 代替 Calendar,

DateTimeFormatter 代替 SimpleDateFormat,官方給出的解釋:simple beautiful strong immutable thread-safe。

12/36

阿里巴巴 Java 開發手冊

6. 【強制】高併發時,同步呼叫應該去考量鎖的效能損耗。能用無鎖資料結構,就不要用鎖;能

鎖區塊,就不要鎖整個方法體;能用物件鎖,就不要用類鎖。

說明:儘可能使加鎖的程式碼塊工作量儘可能的小,避免在鎖程式碼塊中呼叫 RPC 方法。

7. 【強制】對多個資源、資料庫表、物件同時加鎖時,需要保持一致的加鎖順序,否則可能會造

成死鎖。

說明:執行緒一需要對錶 A、B、C 依次全部加鎖後才可以進行更新操作,那麼執行緒二的加鎖順序

也必須是 A、B、C,否則可能出現死鎖。

8. 【強制】併發修改同一記錄時,避免更新丟失,需要加鎖。要麼在應用層加鎖,要麼在快取加

鎖,要麼在資料庫層使用樂觀鎖,使用 version 作為更新依據。

說明:如果每次訪問衝突概率小於 20%,推薦使用樂觀鎖,否則使用悲觀鎖。樂觀鎖的重試次

數不得小於 3 次。

9. 【強制】多執行緒並行處理定時任務時,Timer 執行多個 TimeTask 時,只要其中之一沒有捕獲

丟擲的異常,其它任務便會自動終止執行,使用 ScheduledExecutorService 則沒有這個問題。

10. 【推薦】使用 CountDownLatch 進行非同步轉同步操作,每個執行緒退出前必須呼叫 countDown

相關推薦

阿里程式碼風格

  Table of Contents 前言 目錄 一、程式設計規約 (一) 命名風格 (二) 常量定義 (三) 程式碼格式 (四) OOP規約 (五) 集合處理 (六) 併發處理 (七) 控制語句 (八) 註釋規約 二、異常日誌 (

規範自己程式碼風格 安裝 eclipse阿里巴巴Java開發規約外掛

2017年10月14日,阿里巴巴在杭州雲棲大會上,正式釋出了由阿里巴巴 P3C 專案組,經過 247 天的持續研發,正式釋出眾所期待的 《阿里巴巴 Java 開發規約》的掃描外掛! 該外掛已經在 Github 上開源,有興趣的可以直接去看看。 大概有以下內容 雖

#程式設計師吐槽阿里程式碼不規範!網友:慢了績效就沒了

一個優秀的開發工程師,他的技術不僅要達到相對靠前的標準,而且平常的程式設計格式也應該要規範,比如程式碼對齊、巢狀等等,這些都是老生常談的話題了,不需要去強調! 有想學習java的程式設計師,可來我們的java學習扣qun:72340,3928免費送java的視訊教程噢!小編是6年java開發

【薦】Angular官方程式碼風格指南 (實用、贊)

原文出處:https://blog.csdn.net/fen747042796/article/details/78880424 本文為筆者對Angular官網風格指南的整理版本,刪除/增加了部分內容。另外,原文對每個規範都作出了原因的解釋,個別還有示例,需要的請點選檢視原文。 原連結:英文

VS Code書寫vue專案配置 eslint+prettier 統一程式碼風格

前言 以前公司的vue專案只是我一個人在寫,程式碼風格統一,但是後來隨著團隊增加,統一的程式碼風格就越來越重要。我的主力工具是sublime,ws輔助,vscode基本很少使用(就下載安裝放在冷宮),但是聽說用來寫vue專案還不錯,就開啟了一番折騰。當然工具麼,沒有誰好誰壞了~~ 不盲目站

看看這些被同事噴的JS程式碼風格你寫過多少

作者:殷榮檜@騰訊 目錄: 一、變數相關 二、函式相關 三、儘量使用ES6,有可以能的話ES7中新語法   現在寫程式碼比以前好多了,程式碼的格式都有eslint,prettier,babel(寫新版語法)這些來保證,然而,技術手段再高階都不能解決程式碼可讀性(程式碼能否被未來的自己和同事看懂)的問

不同的verilog程式碼風格看RTL檢視之一

轉自:http://www.eepw.com.cn/article/268450.htm 作者:時間:2015-01-21來源:網路收藏       剛開始玩CPLD/FPGA開發板的時候使用的一塊基於EPM240T100的板子,alter的這塊晶片雖說功耗小體積

Python程式碼風格指南&程式設計規範

1 前言         紛吾既有此內美兮,又重之以修能。 ---- 屈原《離騷》  1.1 編寫目的         本文用於指導我司使用python語言進行開發的人員。 1.2 範

CLANG技術分享系列二:程式碼風格檢查(A CLANG PLUGIN APPROACH)

轉:http://kangwang1988.github.io/tech/2016/10/31/check-code-style-using-clang-plugin.html 背景 一致的程式碼風格檢查已經是老生常談了,統一規範的程式碼風格不僅可提高程式碼的可讀性,可維護性,減少問題

招聘靠譜程式設計師系列:1 程式碼風格優化與糾錯

問:風格糾錯 答: 使用NS_ENUM而不是C語言型別的列舉enum typedef NS_ENUM(NSInteget, XBYGender) { //使用gender比sex正式 XBYGenderMan, XBYGenderWo

儲存程式碼時格式化程式碼風格

儲存時格式化程式碼風格 在使用VSCode時,我們經常會利用一些工具來幫我們做一些事情,比如統一團隊成員的程式碼風格。 下面列舉幾種可以在儲存檔案時按照固定的程式碼風格格式化檔案的方法 使用Formatting 使用lintOnSave 使用ESlint外掛

如何寫出符合 Python 審美的程式碼風格

每個人都有自己的程式碼風格,隨著寫的行數增加,自己對於程式碼的審美也會變的不一樣,這就像是一個逐漸蛻變的過程,每過一段時間回頭再去看看自己之前寫的程式碼就會生出一種「這麼醜的玩意兒竟然是我寫的」這種感慨。   之前不論是寫 C 或者是 C++ 的時候,對於程式碼風格的好壞觀感完全是憑著自己的主觀

Prettier來統一程式碼風格

prettier是一款解決程式碼風格問題的程式碼格式化工具,功能強大,簡單易用,支援多語言,減少配置項。 前端開發過程中每個人寫JavaScript的程式碼風格都不一樣,又不能說別人寫的程式碼有問題,這都是習慣的問題,比如有的人寫if-else語句有以下的寫法: if(name == 'zeng'){

PHP 程式碼風格規範 PSR-2 (中文版)

PHP 程式碼風格規範 PSR-2 本篇規範是 PSR-1 基本程式碼規範的繼承與擴充套件。 本規範希望通過制定一系列規範化PHP程式碼的規則,以減少在瀏覽不同作者的程式碼時,因代 碼風格的不同而造成不便。 當多名程式設計師在多個專案中合作時,就需要一個共同的編碼規範, 而本文中的風格規範源自 於多個不同專案

IDEA2018.2 阿里程式碼檢查外掛 MyBatis plugin安裝

宣告使用的IDEA 2018 .2版本; 在plugins  中搜索Alibaba  Java  Coding  Guidelines  點選安裝,重啟  IDEA 生效;    在 plugi

阿里程式碼檢測p3c外掛安裝使用規則

阿里在杭州雲棲大會上,正式釋出眾所期待的《阿里巴巴Java開發規約》掃描外掛! 該外掛由阿里巴巴P3C專案組研發。這個專案組是阿里巴巴開發愛好者自發組織形成的虛擬專案組,把《阿里巴巴Java開發規約》強制條目轉化成自動化外掛,並實現部分的自動程式設計。 外掛的下載地址: https:/

hough變換 正在的c程式碼風格實現

影象中直線的檢測 -- Hough變換原理   一、簡單介紹 Hough變換是影象處理中從影象中識別幾何形狀的基本方法之一。Hough變換的基本原理在於利用點與線的對偶性,將原始影象空間的給定的曲線通過曲線表

例項詳解Vue專案使用eslint + prettier規範程式碼風格

團隊開發的專案,如果沒有對程式碼風格作要求,有多少團隊成員,就當然會出現多少種不同的程式碼風格。因此,我們需要一種能夠統一團隊程式碼風格的工具,作為強制性的規範,統一整個專案的程式碼風格。 幸好,我們有 eslint 和 prettier 。 eslint VS

Jenkins上的lint程式碼靜態測試和程式碼風格檢查cpplint

最近欲使用Jenkins來構建自動化測試體系。除正常的動態測試的自動化,希望新增靜態測試到框架中。於是選定cppcheck和cpplint來作為程式碼靜態走查和程式碼風格檢查的工具。下面是使用jenkins來進行靜態測試的準備工作: 一、Jenkins的程式碼靜態走查  工具選擇:因為我們主要是C++程式碼