阿里巴巴 Java 開(kāi)發(fā)手冊(cè)(一)

目錄

一、 編程規(guī)約................................................................................................................................................................................1

(一)命名規(guī)約................................................................................................................................................................1

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

(三)格式規(guī)約................................................................................................................................................................4

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

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

(六)并發(fā)處理.............................................................................................................................................................12

(七)控制語(yǔ)句.............................................................................................................................................................15

(八)注釋規(guī)約.............................................................................................................................................................16

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

二、異常日志.............................................................................................................................................................................19

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

(二)日志規(guī)約.............................................................................................................................................................20

三、MySQL規(guī)約.......................................................................................................................................................................22

(一)建表規(guī)約.............................................................................................................................................................22

(二)索引規(guī)約.............................................................................................................................................................23

(三) SQL規(guī)約.............................................................................................................................................................25

(四) ORM規(guī)約.............................................................................................................................................................26

四、工程規(guī)約.............................................................................................................................................................................27

(一)應(yīng)用分層.............................................................................................................................................................27

(二)二方庫(kù)規(guī)約.........................................................................................................................................................28

(三)服務(wù)器規(guī)約.........................................................................................................................................................30

五、安全規(guī)約.............................................................................................................................................................................31

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——1/34

Java開(kāi)發(fā)手冊(cè)

1.0.0阿里巴巴集團(tuán)技術(shù)團(tuán)隊(duì)2017.2.9正式版

一、 編程規(guī)約

(一)命名規(guī)約

1.【強(qiáng)制】 代碼中的命名均不能以下劃線或美元符號(hào)開(kāi)始,也不能以下劃線或美元符號(hào)結(jié)束。

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

2.【強(qiáng)制】 代碼中的命名嚴(yán)禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。

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

也要避免采用。

反例:DaZhePromotion [打折]/getPingfenByName() [評(píng)分]/int某變量= 3

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

3.【強(qiáng)制】類名使用UpperCamelCase風(fēng)格,必須遵從駝峰形式,但以下情形例外:(領(lǐng)域模型

的相關(guān)命名)DO/BO/DTO/VO等。

正例:MarcoPolo/UserDO/XmlService/TcpUdpDeal/TaPromotion

反例:macroPolo/UserDo/XMLService/TCPUDPDeal/TAPromotion

4.【強(qiáng)制】方法名、參數(shù)名、成員變量、局部變量都統(tǒng)一使用lowerCamelCase風(fēng)格,必須遵從

駝峰形式。

正例:localValue/getHttpMessage()/inputUserId

5.【 強(qiáng)制】常量命名全部大寫,單詞間用下劃線隔開(kāi),力求語(yǔ)義表達(dá)完整清楚,不要嫌名字長(zhǎng)。

正例:MAX_STOCK_COUNT

反例:MAX_COUNT

6.【強(qiáng)制】抽象類命名使用Abstract或Base開(kāi)頭;異常類命名使用Exception結(jié)尾;測(cè)試類

命名以它要測(cè)試的類的名稱開(kāi)始,以Test結(jié)尾。

7.【強(qiáng)制】中括號(hào)是數(shù)組類型的一部分,數(shù)組定義如下:String[]args;

反例:請(qǐng)勿使用String args[]的方式來(lái)定義。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——2/34

8.【強(qiáng)制】POJO類中布爾類型的變量,都不要加is,否則部分框架解析會(huì)引起序列化錯(cuò)誤。

反例:定義為基本數(shù)據(jù)類型boolean isSuccess;的屬性,它的方法也是isSuccess(),RPC

框架在反向解析的時(shí)候,“以為”對(duì)應(yīng)的屬性名稱是success,導(dǎo)致屬性獲取不到,進(jìn)而拋出異

常。

9.【強(qiáng)制】包名統(tǒng)一使用小寫,點(diǎn)分隔符之間有且僅有一個(gè)自然語(yǔ)義的英語(yǔ)單詞。包名統(tǒng)一使用

單數(shù)形式,但是類名如果有復(fù)數(shù)含義,類名可以使用復(fù)數(shù)形式。

正例:應(yīng)用工具類包名為com.alibaba.open.util、類名為MessageUtils(此規(guī)則參考

spring的框架結(jié)構(gòu))

10.【強(qiáng)制】杜絕完全不規(guī)范的縮寫, 避免望文不知義。

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

隨意縮寫嚴(yán)重降低了代碼的可閱讀性。

11.【推薦】如果使用到了設(shè)計(jì)模式,建議在類名中體現(xiàn)出具體模式。

說(shuō)明:將設(shè)計(jì)模式體現(xiàn)在名字中,有利于閱讀者快速理解架構(gòu)設(shè)計(jì)思想。

正例:public class OrderFactory;

public class LoginProxy;

public class ResourceObserver;

12.【推薦】接口類中的方法和屬性不要加任何修飾符號(hào)(public也不要加),保持代碼的簡(jiǎn)潔

性,并加上有效的Javadoc注釋。盡量不要在接口里定義變量,如果一定要定義變量,肯定是

與接口方法相關(guān),并且是整個(gè)應(yīng)用的基礎(chǔ)常量。

正例:接口方法簽名:void f();

接口基礎(chǔ)常量表示:String COMPANY= "alibaba";

反例:接口方法定義:public abstractvoid f();

說(shuō)明:JDK8中接口允許有默認(rèn)實(shí)現(xiàn),那么這個(gè)default方法,是對(duì)所有實(shí)現(xiàn)類都有價(jià)值的默

認(rèn)實(shí)現(xiàn)。

13.接口和實(shí)現(xiàn)類的命名有兩套規(guī)則:

1)【強(qiáng)制】對(duì)于Service和DAO類,基于SOA的理念,暴露出來(lái)的服務(wù)一定是接口,內(nèi)部

的實(shí)現(xiàn)類用Impl的后綴與接口區(qū)別。

正例:CacheServiceImpl實(shí)現(xiàn)CacheService接口。

2)【推薦】 如果是形容能力的接口名稱,取對(duì)應(yīng)的形容詞做接口名(通常是–able的形式)。

正例:AbstractTranslator實(shí)現(xiàn)Translatable。

14.【參考】枚舉類名建議帶上Enum后綴,枚舉成員名稱需要全大寫,單詞間用下劃線隔開(kāi)。

說(shuō)明:枚舉其實(shí)就是特殊的常量類,且構(gòu)造方法被默認(rèn)強(qiáng)制是私有。

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

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——3/34

15.【參考】各層命名規(guī)約:

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

1)獲取單個(gè)對(duì)象的方法用get做前綴。

2)獲取多個(gè)對(duì)象的方法用list做前綴。

3)獲取統(tǒng)計(jì)值的方法用count做前綴。

4)插入的方法用save(推薦)或insert做前綴。

5)刪除的方法用remove(推薦)或delete做前綴。

6)修改的方法用update做前綴。

B)領(lǐng)域模型命名規(guī)約

1)數(shù)據(jù)對(duì)象:xxxDO,xxx即為數(shù)據(jù)表名。

2)數(shù)據(jù)傳輸對(duì)象:xxxDTO,xxx為業(yè)務(wù)領(lǐng)域相關(guān)的名稱。

3)展示對(duì)象:xxxVO,xxx一般為網(wǎng)頁(yè)名稱。

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

(二)常量定義

1.【強(qiáng)制】不允許出現(xiàn)任何魔法值(即未經(jīng)定義的常量)直接出現(xiàn)在代碼中。

反例:String key="Id#taobao_"+tradeId;

cache.put(key,value);

2.【強(qiáng)制】long或者Long初始賦值時(shí),必須使用大寫的L,不能是小寫的l,小寫容易跟數(shù)字

1混淆,造成誤解。

說(shuō)明:Long a= 2l;寫的是數(shù)字的21,還是Long型的2?

3.【推薦】不要使用一個(gè)常量類維護(hù)所有常量,應(yīng)該按常量功能進(jìn)行歸類,分開(kāi)維護(hù)。如:緩存

相關(guān)的常量放在類:CacheConsts下;系統(tǒng)配置相關(guān)的常量放在類:ConfigConsts下。

說(shuō)明:大而全的常量類,非得使用查找功能才能定位到修改的常量,不利于理解和維護(hù)。

4.【推薦】常量的復(fù)用層次有五層:跨應(yīng)用共享常量、應(yīng)用內(nèi)共享常量、子工程內(nèi)共享常量、包

內(nèi)共享常量、類內(nèi)共享常量。

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

2)應(yīng)用內(nèi)共享常量:放置在一方庫(kù)的modules中的constant目錄下。

反例:易懂變量也要統(tǒng)一定義成應(yīng)用內(nèi)共享常量,兩位攻城師在兩個(gè)類中分別定義 了

表示“是”的變量:

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

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

A.YES.equals(B.YES),預(yù)期是true,但實(shí)際返回為false,導(dǎo)致產(chǎn)生線上問(wèn)題。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——4/34

3)子工程內(nèi)部共享常量:即在當(dāng)前子工程的constant目錄下。

4)包內(nèi)共享常量:即在當(dāng)前包下單獨(dú)的constant目錄下。

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

5.【推薦】如果變量值僅在一個(gè)范圍內(nèi)變化用Enum類。如果還帶有名稱之外的延伸屬性,必須

使用Enum類,下面正例中的數(shù)字就是延伸信息,表示星期幾。

正例:public Enum{MONDAY(1),TUESDAY(2),WEDNESDAY(3),THURSDAY(4),FRIDAY(5),

SATURDAY(6),SUNDAY(7);}

(三)格式規(guī)約

1.【強(qiáng)制】大括號(hào)的使用約定。如果是大括號(hào)內(nèi)為空,則簡(jiǎn)潔地寫成{}即可,不需要換行;如果

是非空代碼塊則:

1)左大括號(hào)前不換行。

2)左大括號(hào)后換行。

3)右大括號(hào)前換行。

4)右大括號(hào)后還有else等代碼則不換行;表示終止右大括號(hào)后必須換行。

2.【強(qiáng)制】 左括號(hào)和后一個(gè)字符之間不出現(xiàn)空格;同樣,右括號(hào)和前一個(gè)字符之間也不出現(xiàn)空

格。詳見(jiàn)第5條下方正例提示。

3.【強(qiáng)制】if/for/while/switch/do等保留字與左右括號(hào)之間都必須加空格。

4.【強(qiáng)制】任何運(yùn)算符左右必須加一個(gè)空格。

說(shuō)明:運(yùn)算符包括賦值運(yùn)算符=、邏輯運(yùn)算符&&、加減乘除符號(hào)、三目運(yùn)行符等。

5.【強(qiáng)制】 縮進(jìn)采用4個(gè)空格,禁止使用tab字符。

說(shuō)明:如果使用tab縮進(jìn),必須設(shè)置1個(gè)tab為4個(gè)空格。IDEA設(shè)置tab為4個(gè)空格時(shí),

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

正例:(涉及1-5點(diǎn))

public static void main(String args[]) {

//縮進(jìn)4個(gè)空格

String say = "hello";

//運(yùn)算符的左右必須有一個(gè)空格

int flag = 0;

//關(guān)鍵詞if與括號(hào)之間必須有一個(gè)空格,括號(hào)內(nèi)的f與左括號(hào),0與右括號(hào)不需要空格

if (flag == 0) {

System.out.println(say);

}

//左大括號(hào)前加空格且不換行;左大括號(hào)后換行

if (flag == 1) {

System.out.println("world");

//右大括號(hào)前換行,右大括號(hào)后有else,不用換行

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——5/34

} else {

System.out.println("ok");

//在右大括號(hào)后直接結(jié)束,則必須換行

}

}

6.【強(qiáng)制】單行字符數(shù)限制不超過(guò)120個(gè),超出需要換行,換行時(shí)遵循如下原則:

1) 第二行相對(duì)第一行縮進(jìn)4個(gè)空格,從第三行開(kāi)始,不再繼續(xù)縮進(jìn),參考示例。

2)運(yùn)算符與下文一起換行。

3)方法調(diào)用的點(diǎn)符號(hào)與下文一起換行。

4)在多個(gè)參數(shù)超長(zhǎng),逗號(hào)后進(jìn)行換行。

5)在括號(hào)前不要換行,見(jiàn)反例。

正例:

StringBuffer sb = new StringBuffer();

//超過(guò)120個(gè)字符的情況下,換行縮進(jìn)4個(gè)空格,并且方法前的點(diǎn)符號(hào)一起換行

sb.append("zi").append("xin")...

.append("huang")...

.append("huang")...

.append("huang");

反例:

StringBuffer sb = new StringBuffer();

//超過(guò)120個(gè)字符的情況下,不要在括號(hào)前換行

sb.append("zi").append("xin")...append

("huang");

//參數(shù)很多的方法調(diào)用可能超過(guò)120個(gè)字符, 不要在逗號(hào)前換行

method(args1, args2, args3, ...

, argsX);

7.【強(qiáng)制】方法參數(shù)在定義和傳入時(shí),多個(gè)參數(shù)逗號(hào)后邊必須加空格。

正例:下例中實(shí)參的"a",后邊必須要有一個(gè)空格。

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

8.【強(qiáng)制】IDE的text file encoding設(shè)置為UTF-8; IDE中文件的換行符使用Unix格式,

不要使用windows格式。

9.【推薦】沒(méi)有必要增加若干空格來(lái)使某一行的字符與上一行的相應(yīng)字符對(duì)齊。

正例:

int a = 3;

long b = 4L;

float c = 5F;

StringBuffer sb = new StringBuffer();

說(shuō)明:增加sb這個(gè)變量,如果需要對(duì)齊,則給a、b、c都要增加幾個(gè)空格,在變量比較多的

情況下,是一種累贅的事情。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——6/34

10.【推薦】方法體內(nèi)的執(zhí)行語(yǔ)句組、變量的定義語(yǔ)句組、不同的業(yè)務(wù)邏輯之間或者不同的語(yǔ)義

之間插入一個(gè)空行。相同業(yè)務(wù)邏輯和語(yǔ)義之間不需要插入空行。

說(shuō)明:沒(méi)有必要插入多行空格進(jìn)行隔開(kāi)。

(四)OOP規(guī)約

1.【強(qiáng)制】避免通過(guò)一個(gè)類的對(duì)象引用訪問(wèn)此類的靜態(tài)變量或靜態(tài)方法,無(wú)謂增加編譯器解析成

本,直接用類名來(lái)訪問(wèn)即可。

2.【強(qiáng)制】所有的覆寫方法,必須加@Override注解。

反例:getObject()與get0bject()的問(wèn)題。一個(gè)是字母的O,一個(gè)是數(shù)字的0,加@Override

可以準(zhǔn)確判斷是否覆蓋成功。另外,如果在抽象類中對(duì)方法簽名進(jìn)行修改,其實(shí)現(xiàn)類會(huì)馬上編

譯報(bào)錯(cuò)。

3.【強(qiáng)制】相同參數(shù)類型,相同業(yè)務(wù)含義,才可以使用Java的可變參數(shù),避免使用Object。

說(shuō)明:可變參數(shù)必須放置在參數(shù)列表的最后。(提倡同學(xué)們盡量不用可變參數(shù)編程)

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

4.【強(qiáng)制】對(duì)外暴露的接口簽名,原則上不允許修改方法簽名,避免對(duì)接口調(diào)用方產(chǎn)生影響。接

口過(guò)時(shí)必須加@Deprecated注解,并清晰地說(shuō)明采用的新接口或者新服務(wù)是什么。

5.【強(qiáng)制】不能使用過(guò)時(shí)的類或方法。

說(shuō)明:java.net.URLDecoder中的方法decode(String encodeStr)這個(gè)方法已經(jīng)過(guò)時(shí),應(yīng)

該使用雙參數(shù)decode(String source, String encode)。接口提供方既然明確是過(guò)時(shí)接口,

那么有義務(wù)同時(shí)提供新的接口;作為調(diào)用方來(lái)說(shuō),有義務(wù)去考證過(guò)時(shí)方法的新實(shí)現(xiàn)是什么。

6.【強(qiáng)制】Object的equals方法容易拋空指針異常,應(yīng)使用常量或確定有值的對(duì)象來(lái)調(diào)用

equals。

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

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

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

7.【強(qiáng)制】所有的相同類型的包裝類對(duì)象之間值的比較,全部使用equals方法比較。

說(shuō)明:對(duì)于Integer var=?在-128至127之間的賦值,Integer對(duì)象是在

IntegerCache.cache產(chǎn)生,會(huì)復(fù)用已有對(duì)象,這個(gè)區(qū)間內(nèi)的Integer值可以直接使用==進(jìn)行

判斷,但是這個(gè)區(qū)間之外的所有數(shù)據(jù),都會(huì)在堆上產(chǎn)生,并不會(huì)復(fù)用已有對(duì)象,這是一個(gè)大坑,

推薦使用equals方法進(jìn)行判斷。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——7/34

8.【強(qiáng)制】關(guān)于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標(biāo)準(zhǔn)如下:

1)所有的POJO類屬性必須使用包裝數(shù)據(jù)類型。

2)RPC方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型。

3)所有的局部變量【 推薦】 使用基本數(shù)據(jù)類型。

說(shuō)明:POJO類屬性沒(méi)有初值是提醒使用者在需要使用時(shí),必須自己顯式地進(jìn)行賦值,任何

NPE問(wèn)題,或者入庫(kù)檢查,都由使用者來(lái)保證。

正例:數(shù)據(jù)庫(kù)的查詢結(jié)果可能是null,因?yàn)樽詣?dòng)拆箱,用基本數(shù)據(jù)類型接收有NPE風(fēng)險(xiǎn)。

反例:比如顯示成交總額漲跌情況,即正負(fù)x%,x為基本數(shù)據(jù)類型,調(diào)用的RPC服務(wù),調(diào)用

不成功時(shí),返回的是默認(rèn)值,頁(yè)面顯示:0%,這是不合理的,應(yīng)該顯示成中劃線-。所以包裝

數(shù)據(jù)類型的null值,能夠表示額外的信息, 如:遠(yuǎn)程調(diào)用失敗,異常退出。

9.【強(qiáng)制】定義DO/DTO/VO等POJO類時(shí),不要設(shè)定任何屬性默認(rèn)值。

反例:POJO類的gmtCreate默認(rèn)值為new Date();但是這個(gè)屬性在數(shù)據(jù)提取時(shí)并沒(méi)有置入具

體值,在更新其它字段時(shí)又附帶更新了此字段,導(dǎo)致創(chuàng)建時(shí)間被修改成當(dāng)前時(shí)間。

10.【強(qiáng)制】序列化類新增屬性時(shí),請(qǐng)不要修改serialVersionUID字段,避免反序列失敗;如

果完全不兼容升級(jí),避免反序列化混亂,那么請(qǐng)修改serialVersionUID值。

說(shuō)明:注意serialVersionUID不一致會(huì)拋出序列化運(yùn)行時(shí)異常。

11.【強(qiáng)制】構(gòu)造方法里面禁止加入任何業(yè)務(wù)邏輯,如果有初始化邏輯,請(qǐng)放在init方法中。

12.【強(qiáng)制】POJO類必須寫toString方法。使用IDE的中工具:source>generate toString

時(shí),如果繼承了另一個(gè)POJO類,注意在前面加一下super.toString。

說(shuō)明:在方法執(zhí)行拋出異常時(shí),可以直接調(diào)用POJO的toString()方法打印其屬性值,便于排

查問(wèn)題。

13.【推薦】使用索引訪問(wèn)用String的split方法得到的數(shù)組時(shí),需做最后一個(gè)分隔符后有無(wú)

內(nèi)容的檢查,否則會(huì)有拋IndexOutOfBoundsException的風(fēng)險(xiǎn)。

說(shuō)明:

String str = "a,b,c,,";

String[] ary = str.split(",");

//預(yù)期大于3,結(jié)果是3

System.out.println(ary.length);

14.【推薦】當(dāng)一個(gè)類有多個(gè)構(gòu)造方法,或者多個(gè)同名方法,這些方法應(yīng)該按順序放置在一起,

便于閱讀。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——8/34

15.【推薦】 類內(nèi)方法定義順序依次是:公有方法或保護(hù)方法>私有方法>getter/setter

方法。

說(shuō)明:公有方法是類的調(diào)用者和維護(hù)者最關(guān)心的方法,首屏展示最好;保護(hù)方法雖然只是子類

關(guān)心,也可能是“模板設(shè)計(jì)模式”下的核心方法;而私有方法外部一般不需要特別關(guān)心,是一個(gè)

黑盒實(shí)現(xiàn);因?yàn)榉椒ㄐ畔r(jià)值較低,所有Service和DAO的getter/setter方法放在類體最

后。

16.【推薦】setter方法中,參數(shù)名稱與類成員變量名稱一致,this.成員名=參數(shù)名。在

getter/setter方法中,盡量不要增加業(yè)務(wù)邏輯,增加排查問(wèn)題的難度。

反例:

public Integer getData(){

if(true) {

return data + 100;

} else {

return data - 100;

}

}

17.【推薦】循環(huán)體內(nèi),字符串的聯(lián)接方式,使用StringBuilder的append方法進(jìn)行擴(kuò)展。

反例:

String str = "start";

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

str = str + "hello";

}

說(shuō)明:反編譯出的字節(jié)碼文件顯示每次循環(huán)都會(huì)new出一個(gè)StringBuilder對(duì)象,然后進(jìn)行

append操作,最后通過(guò)toString方法返回String對(duì)象,造成內(nèi)存資源浪費(fèi)。

18.【推薦】final可提高程序響應(yīng)效率,聲明成final的情況:

1)不需要重新賦值的變量,包括類屬性、局部變量。

2)對(duì)象參數(shù)前加final,表示不允許修改引用的指向。

3)類方法確定不允許被重寫。

19.【推薦】慎用Object的clone方法來(lái)拷貝對(duì)象。

說(shuō)明:對(duì)象的clone方法默認(rèn)是淺拷貝,若想實(shí)現(xiàn)深拷貝需要重寫clone方法實(shí)現(xiàn)屬性對(duì)象

的拷貝。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——9/34

20.【推薦】類成員與方法訪問(wèn)控制從嚴(yán):

1)如果不允許外部直接通過(guò)new來(lái)創(chuàng)建對(duì)象,那么構(gòu)造方法必須是private。

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

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

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

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

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

7)類成員方法只供類內(nèi)部調(diào)用,必須是private。

8)類成員方法只對(duì)繼承類公開(kāi),那么限制為protected。

說(shuō)明:任何類、方法、參數(shù)、變量,嚴(yán)控訪問(wèn)范圍。過(guò)寬泛的訪問(wèn)范圍,不利于模塊解耦。思

考:如果是一個(gè)private的方法,想刪除就刪除,可是一個(gè)public的Service方法,或者一

個(gè)public的成員變量,刪除一下,不得手心冒點(diǎn)汗嗎?變量像自己的小孩,盡量在自己的視

線內(nèi),變量作用域太大,如果無(wú)限制的到處跑,那么你會(huì)擔(dān)心的。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——10/34

(五)集合處理

1.【強(qiáng)制】 關(guān)于hashCode和equals的處理,遵循如下規(guī)則:

1) 只要重寫equals,就必須重寫hashCode。

2) 因?yàn)镾et存儲(chǔ)的是不重復(fù)的對(duì)象,依據(jù)hashCode和equals進(jìn)行判斷,所以Set存儲(chǔ)的

對(duì)象必須重寫這兩個(gè)方法。

3) 如果自定義對(duì)象做為Map的鍵,那么必須重寫hashCode和equals。

正例:String重寫了hashCode和equals方法,所以我們可以非常愉快地使用String對(duì)象

作為key來(lái)使用。

2.【強(qiáng)制】ArrayList的subList結(jié)果不可強(qiáng)轉(zhuǎn)成ArrayList,否則會(huì)拋出ClassCastException

異常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList ;

說(shuō)明:subList返回的是ArrayList的內(nèi)部類SubList,并不是ArrayList,而是

ArrayList的一個(gè)視圖,對(duì)于SubList子列表的所有操作最終會(huì)反映到原列表上。

3.【強(qiáng)制】 在subList場(chǎng)景中,高度注意對(duì)原集合元素個(gè)數(shù)的修改,會(huì)導(dǎo)致子列表的遍歷、增

加、刪除均產(chǎn)生ConcurrentModificationException異常。

4.【強(qiáng)制】使用集合轉(zhuǎn)數(shù)組的方法,必須使用集合的toArray(T[] array),傳入的是類型完全

一樣的數(shù)組,大小就是list.size()。

反例:直接使用toArray無(wú)參方法存在問(wèn)題,此方法返回值只能是Object[]類,若強(qiáng)轉(zhuǎn)其它

類型數(shù)組將出現(xiàn)ClassCastException錯(cuò)誤。

正例:

List list = new ArrayList(2);

list.add("guan");

list.add("bao");

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

array = list.toArray(array);

說(shuō)明:使用toArray帶參方法,入?yún)⒎峙涞臄?shù)組空間不夠大時(shí),toArray方法內(nèi)部將重新分配

內(nèi)存空間,并返回新數(shù)組地址;如果數(shù)組元素大于實(shí)際所需,下標(biāo)為[ list.size() ]的數(shù)組

元素將被置為null,其它數(shù)組元素保持原值,因此最好將方法入?yún)?shù)組大小定義與集合元素

個(gè)數(shù)一致。

5.【強(qiáng)制】使用工具類Arrays.asList()把數(shù)組轉(zhuǎn)換成集合時(shí),不能使用其修改集合相關(guān)的方

法,它的add/remove/clear方法會(huì)拋出UnsupportedOperationException異常。

說(shuō)明:asList的返回對(duì)象是一個(gè)Arrays內(nèi)部類,并沒(méi)有實(shí)現(xiàn)集合的修改方法。Arrays.asList

體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺(tái)的數(shù)據(jù)仍是數(shù)組。

String[] str = new String[] { "a", "b" };

List list = Arrays.asList(str);

第一種情況:list.add("c");運(yùn)行時(shí)異常。

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

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——11/34

6.【強(qiáng)制】泛型通配符來(lái)接收返回的數(shù)據(jù),此寫法的泛型集合不能使用add方

法。

說(shuō)明:蘋果裝箱后返回一個(gè)對(duì)象,此對(duì)象就不能往里加任何水果,包括

蘋果。

7.【強(qiáng)制】不要在foreach循環(huán)里進(jìn)行元素的remove/add操作。remove元素請(qǐng)使用Iterator

方式,如果并發(fā)操作,需要對(duì)Iterator對(duì)象加鎖。

反例:

List a = new ArrayList();

a.add("1");

a.add("2");

for (String temp : a) {

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

a.remove(temp);

}

}

說(shuō)明:以上代碼的執(zhí)行結(jié)果肯定會(huì)出乎大家的意料,那么試一下把“1”換成“2”,會(huì)是同樣的

結(jié)果嗎?

正例:

Iterator it = a.iterator();

while(it.hasNext()){

String temp = it.next();

if(刪除元素的條件){

it.remove();

}

}

8.【強(qiáng)制】 在JDK7版本以上,Comparator要滿足自反性,傳遞性,對(duì)稱性,不然Arrays.sort,

Collections.sort會(huì)報(bào)IllegalArgumentException異常。

說(shuō)明:

1)自反性:x,y的比較結(jié)果和y,x的比較結(jié)果相反。

2)傳遞性:x>y,y>z,則x>z。

3)對(duì)稱性:x=y,則x,z比較結(jié)果和y,z比較結(jié)果相同。

反例:下例中沒(méi)有處理相等的情況,實(shí)際使用中可能會(huì)出現(xiàn)異常:

new Comparator() {

@Override

public int compare(Student o1, Student o2) {

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

}

}

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——12/34

9.【推薦】集合初始化時(shí),盡量指定集合初始值大小。

說(shuō)明:ArrayList盡量使用ArrayList(int initialCapacity)初始化。

10.【推薦】使用entrySet遍歷Map類集合KV,而不是keySet方式進(jìn)行遍歷。

說(shuō)明:keySet其實(shí)是遍歷了2次,一次是轉(zhuǎn)為Iterator對(duì)象,另一次是從hashMap中取出

key所對(duì)應(yīng)的value。而entrySet只是遍歷了一次就把key和value都放到了entry中,效

率更高。如果是JDK8,使用Map.foreach方法。

正例:values()返回的是V值集合,是一個(gè)list集合對(duì)象;keySet()返回的是K值集合,是

一個(gè)Set集合對(duì)象;entrySet()返回的是K-V值組合集合。

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

Hashtable不允許為null不允許為nullDictionary線程安全

ConcurrentHashMap不允許為null不允許為nullAbstractMap分段鎖技術(shù)

TreeMap不允許為null允許為nullAbstractMap線程不安全

HashMap允許為null允許為nullAbstractMap線程不安全

反例:由于HashMap的干擾,很多人認(rèn)為ConcurrentHashMap是可以置入null值,注意存儲(chǔ)

null值時(shí)會(huì)拋出NPE異常。

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

不穩(wěn)定性(unorder)帶來(lái)的負(fù)面影響。

說(shuō)明:穩(wěn)定性指集合每次遍歷的元素次序是一定的。有序性是指遍歷的結(jié)果是按某種比較規(guī)則

依次排列的。如:ArrayList是order/unsort;HashMap是unorder/unsort;TreeSet是

order/sort。

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

contains方法進(jìn)行遍歷、對(duì)比、 去重操作。

(六)并發(fā)處理

1.【強(qiáng)制】 獲取單例對(duì)象需要保證線程安全,其中的方法也要保證線程安全。

說(shuō)明:資源驅(qū)動(dòng)類、工具類、單例工廠類都需要注意。

2.【強(qiáng)制】創(chuàng)建線程或線程池時(shí)請(qǐng)指定有意義的線程名稱,方便出錯(cuò)時(shí)回溯。

正例:

public class TimerTaskThread extends Thread {

public TimerTaskThread(){

super.setName("TimerTaskThread"); ...

}

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——13/34

3.【強(qiáng)制】線程資源必須通過(guò)線程池提供,不允許在應(yīng)用中自行顯式創(chuàng)建線程。

說(shuō)明:使用線程池的好處是減少在創(chuàng)建和銷毀線程上所花的時(shí)間以及系統(tǒng)資源的開(kāi)銷,解決資

源不足的問(wèn)題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者

“過(guò)度切換”的問(wèn)題。

4.【強(qiáng)制】線程池不允許使用Executors去創(chuàng)建,而是通過(guò)ThreadPoolExecutor的方式,這樣

的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險(xiǎn)。

說(shuō)明:Executors返回的線程池對(duì)象的弊端如下:

1)FixedThreadPool和SingleThreadPool:

允許的請(qǐng)求隊(duì)列長(zhǎng)度為Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求,從而導(dǎo)致OOM。

2)CachedThreadPool和ScheduledThreadPool:

允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE, 可能會(huì)創(chuàng)建大量的線程,從而導(dǎo)致OOM。

5.【強(qiáng)制】SimpleDateFormat是線程不安全的類,一般不要定義為static變量,如果定義為

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

正例:注意線程安全,使用DateUtils。亦推薦如下處理:

private static final ThreadLocal df = new ThreadLocal() {

@Override

protected DateFormat initialValue() {

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

}

};

說(shuō)明:如果是JDK8的應(yīng)用,可以使用Instant代替Date,LocalDateTime代替Calendar,

DateTimeFormatter代替Simpledateformatter,官方給出的解釋:simple beautiful strong

immutable thread-safe。

6.【強(qiáng)制】高并發(fā)時(shí),同步調(diào)用應(yīng)該去考量鎖的性能損耗。能用無(wú)鎖數(shù)據(jù)結(jié)構(gòu),就不要用鎖;能

鎖區(qū)塊,就不要鎖整個(gè)方法體;能用對(duì)象鎖,就不要用類鎖。

7.【強(qiáng)制】對(duì)多個(gè)資源、數(shù)據(jù)庫(kù)表、對(duì)象同時(shí)加鎖時(shí),需要保持一致的加鎖順序,否則可能會(huì)造

成死鎖。

說(shuō)明:線程一需要對(duì)表A、B、C依次全部加鎖后才可以進(jìn)行更新操作,那么線程二的加鎖順序

也必須是A、B、C,否則可能出現(xiàn)死鎖。

8.【強(qiáng)制】并發(fā)修改同一記錄時(shí),避免更新丟失,要么在應(yīng)用層加鎖,要么在緩存加鎖,要么在

數(shù)據(jù)庫(kù)層使用樂(lè)觀鎖,使用version作為更新依據(jù)。

說(shuō)明:如果每次訪問(wèn)沖突概率小于20%,推薦使用樂(lè)觀鎖,否則使用悲觀鎖。樂(lè)觀鎖的重試次

數(shù)不得小于3次。

9.【強(qiáng)制】多線程并行處理定時(shí)任務(wù)時(shí),Timer運(yùn)行多個(gè)TimeTask時(shí),只要其中之一沒(méi)有捕獲

拋出的異常,其它任務(wù)便會(huì)自動(dòng)終止運(yùn)行,使用ScheduledExecutorService則沒(méi)有這個(gè)問(wèn)題。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——14/34

10.【推薦】使用CountDownLatch進(jìn)行異步轉(zhuǎn)同步操作,每個(gè)線程退出前必須調(diào)用countDown

方法,線程執(zhí)行代碼注意catch異常,確保countDown方法可以執(zhí)行,避免主線程無(wú)法執(zhí)行

至countDown方法,直到超時(shí)才返回結(jié)果。

說(shuō)明:注意,子線程拋出異常堆棧,不能在主線程try-catch到。

11.【推薦】避免Random實(shí)例被多線程使用,雖然共享該實(shí)例是線程安全的,但會(huì)因競(jìng)爭(zhēng)同一

seed導(dǎo)致的性能下降。

說(shuō)明:Random實(shí)例包括java.util.Random的實(shí)例或者M(jìn)ath.random()實(shí)例。

正例:在JDK7之后,可以直接使用API ThreadLocalRandom,在JDK7之前,可以做到每個(gè)

線程一個(gè)實(shí)例。

12.【推薦】通過(guò)雙重檢查鎖(double-checked locking)(在并發(fā)場(chǎng)景)實(shí)現(xiàn)延遲初始化的優(yōu)

化問(wèn)題隱患(可參考The"Double-Checked Locking is Broken"Declaration),推薦問(wèn)題

解決方案中較為簡(jiǎn)單一種(適用于JDK5及以上版本),將目標(biāo)屬性聲明為volatile型。

反例:

class Foo {

private Helper helper = null;

public Helper getHelper() {

if (helper == null) synchronized(this) {

if (helper == null)

helper = new Helper();

}

return helper;

}

// other functions and members...

}

13.【參考】volatile解決多線程內(nèi)存不可見(jiàn)問(wèn)題。對(duì)于一寫多讀,是可以解決變量同步問(wèn)題,

但是如果多寫,同樣無(wú)法解決線程安全問(wèn)題。如果是count++操作,使用如下類實(shí)現(xiàn):

AtomicInteger count=new AtomicInteger(); count.addAndGet(1);如果是JDK8,推

薦使用LongAdder對(duì)象,比AtomicLong性能更好(減少樂(lè)觀鎖的重試次數(shù))。

14.【參考】HashMap在容量不夠進(jìn)行resize時(shí)由于高并發(fā)可能出現(xiàn)死鏈,導(dǎo)致CPU飆升,在

開(kāi)發(fā)過(guò)程中注意規(guī)避此風(fēng)險(xiǎn)。

15.【參考】ThreadLocal無(wú)法解決共享對(duì)象的更新問(wèn)題,ThreadLocal對(duì)象建議使用static

修飾。這個(gè)變量是針對(duì)一個(gè)線程內(nèi)所有操作共有的,所以設(shè)置為靜態(tài)變量,所有此類實(shí)例共享

此靜態(tài)變量 ,也就是說(shuō)在類第一次被使用時(shí)裝載,只分配一塊存儲(chǔ)空間,所有此類的對(duì)象(只

要是這個(gè)線程內(nèi)定義的)都可以操控這個(gè)變量。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——15/34

(七)控制語(yǔ)句

1.【強(qiáng)制】在一個(gè)switch塊內(nèi),每個(gè)case要么通過(guò)break/return等來(lái)終止,要么注釋說(shuō)明程

序?qū)⒗^續(xù)執(zhí)行到哪一個(gè)case為止;在一個(gè)switch塊內(nèi),都必須包含一個(gè)default語(yǔ)句并且

放在最后,即使它什么代碼也沒(méi)有。

2.【強(qiáng)制】在if/else/for/while/do語(yǔ)句中必須使用大括號(hào),即使只有一行代碼,避免使用

下面的形式:if (condition) statements;

3.【推薦】推薦盡量少用else,if-else的方式可以改寫成:

if(condition){

...

return obj;

}

//接著寫else的業(yè)務(wù)邏輯代碼;

說(shuō)明:如果非得使用if()...else if()...else...方式表達(dá)邏輯,【強(qiáng)制】請(qǐng)勿超過(guò)3層,

超過(guò)請(qǐng)使用狀態(tài)設(shè)計(jì)模式。

正例:邏輯上超過(guò)3層的if-else代碼可以使用衛(wèi)語(yǔ)句,或者狀態(tài)模式來(lái)實(shí)現(xiàn)。

4.【推薦】除常用方法(如getXxx/isXxx)等外,不要在條件判斷中執(zhí)行其它復(fù)雜的語(yǔ)句,將復(fù)

雜邏輯判斷的結(jié)果賦值給一個(gè)有意義的布爾變量名,以提高可讀性。

說(shuō)明:很多if語(yǔ)句內(nèi)的邏輯相當(dāng)復(fù)雜,閱讀者需要分析條件表達(dá)式的最終結(jié)果,才能明確什么

樣的條件執(zhí)行什么樣的語(yǔ)句,那么,如果閱讀者分析邏輯表達(dá)式錯(cuò)誤呢?

正例:

//偽代碼如下

boolean existed = (file.open(fileName, "w") != null)&&(...) || (...);

if (existed) {

...

}

反例:

if ((file.open(fileName, "w") != null)&&(...) || (...)) {

...

}

5.【推薦】循環(huán)體中的語(yǔ)句要考量性能,以下操作盡量移至循環(huán)體外處理,如定義對(duì)象、變量、

獲取數(shù)據(jù)庫(kù)連接,進(jìn)行不必要的try-catch操作(這個(gè)try-catch是否可以移至循環(huán)體外)。

6.【推薦】接口入?yún)⒈Wo(hù),這種場(chǎng)景常見(jiàn)的是用于做批量操作的接口。

7.【參考】方法中需要進(jìn)行參數(shù)校驗(yàn)的場(chǎng)景:

1)調(diào)用頻次低的方法。

2)執(zhí)行時(shí)間開(kāi)銷很大的方法,參數(shù)校驗(yàn)時(shí)間幾乎可以忽略不計(jì),但如果因?yàn)閰?shù)錯(cuò)誤導(dǎo)致

中間執(zhí)行回退,或者錯(cuò)誤,那得不償失。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——16/34

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

4)對(duì)外提供的開(kāi)放接口,不管是RPC/API/HTTP接口。

5) 敏感權(quán)限入口。

8.【 參考】方法中不需要參數(shù)校驗(yàn)的場(chǎng)景:

1)極有可能被循環(huán)調(diào)用的方法,不建議對(duì)參數(shù)進(jìn)行校驗(yàn)。但在方法說(shuō)明里必須注明外部參

數(shù)檢查。

2)底層的方法調(diào)用頻度都比較高,一般不校驗(yàn)。畢竟是像純凈水過(guò)濾的最后一道,參數(shù)錯(cuò)

誤不太可能到底層才會(huì)暴露問(wèn)題。一般DAO層與Service層都在同一個(gè)應(yīng)用中,部署在同一

臺(tái)服務(wù)器中,所以DAO的參數(shù)校驗(yàn),可以省略。

3)被聲明成private只會(huì)被自己代碼所調(diào)用的方法,如果能夠確定調(diào)用方法的代碼傳入?yún)?/p>

數(shù)已經(jīng)做過(guò)檢查或者肯定不會(huì)有問(wèn)題,此時(shí)可以不校驗(yàn)參數(shù)。

(八)注釋規(guī)約

1.【強(qiáng)制】 類、類屬性、類方法的注釋必須使用Javadoc規(guī)范,使用/**內(nèi)容*/格式,不得使用

//xxx方式。

說(shuō)明:在IDE編輯窗口中,Javadoc方式會(huì)提示相關(guān)注釋,生成Javadoc可以正確輸出相應(yīng)注

釋;在IDE中,工程調(diào)用方法時(shí),不進(jìn)入方法即可懸浮提示方法、參數(shù)、返回值的意義,提高

閱讀效率。

2.【強(qiáng)制】所有的抽象方法(包括接口中的方法)必須要用Javadoc注釋、除了返回值、參數(shù)、

異常說(shuō)明外,還必須指出該方法做什么事情,實(shí)現(xiàn)什么功能。

說(shuō)明:對(duì)子類的實(shí)現(xiàn)要求,或者調(diào)用注意事項(xiàng),請(qǐng)一并說(shuō)明。

3.【強(qiáng)制】所有的類都必須添加創(chuàng)建者信息。

4.【強(qiáng)制】方法內(nèi)部單行注釋,在被注釋語(yǔ)句上方另起一行,使用//注釋。方法內(nèi)部多行注釋

使用/* */注釋,注意與代碼對(duì)齊。

5.【強(qiáng)制】所有的枚舉類型字段必須要有注釋,說(shuō)明每個(gè)數(shù)據(jù)項(xiàng)的用途。

6.【推薦】與其“半吊子”英文來(lái)注釋,不如用中文注釋把問(wèn)題說(shuō)清楚。專有名詞與關(guān)鍵字保持

英文原文即可。

反例:“TCP連接超時(shí)”解釋成“傳輸控制協(xié)議連接超時(shí)”,理解反而費(fèi)腦筋。

7.【推薦】代碼修改的同時(shí),注釋也要進(jìn)行相應(yīng)的修改,尤其是參數(shù)、返回值、異常、核心邏輯

等的修改。

說(shuō)明:代碼與注釋更新不同步,就像路網(wǎng)與導(dǎo)航軟件更新不同步一樣,如果導(dǎo)航軟件嚴(yán)重滯后,

就失去了導(dǎo)航的意義。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——17/34

8.【參考】注釋掉的代碼盡量要配合說(shuō)明,而不是簡(jiǎn)單的注釋掉。

說(shuō)明:代碼被注釋掉有兩種可能性:1)后續(xù)會(huì)恢復(fù)此段代碼邏輯。2)永久不用。前者如果沒(méi)

有備注信息,難以知曉注釋動(dòng)機(jī)。后者建議直接刪掉(代碼倉(cāng)庫(kù)保存了歷史代碼)。

9.【參考】對(duì)于注釋的要求:第一、能夠準(zhǔn)確反應(yīng)設(shè)計(jì)思想和代碼邏輯;第二、能夠描述業(yè)務(wù)含

義,使別的程序員能夠迅速了解到代碼背后的信息。完全沒(méi)有注釋的大段代碼對(duì)于閱讀者形同

天書,注釋是給自己看的,即使隔很長(zhǎng)時(shí)間,也能清晰理解當(dāng)時(shí)的思路;注釋也是給繼任者看

的,使其能夠快速接替自己的工作。

10.【參考】好的命名、代碼結(jié)構(gòu)是自解釋的,注釋力求精簡(jiǎn)準(zhǔn)確、表達(dá)到位。避免出現(xiàn)注釋的

一個(gè)極端:過(guò)多過(guò)濫的注釋,代碼的邏輯一旦修改,修改注釋是相當(dāng)大的負(fù)擔(dān)。

反例:

// put elephant into fridge

put(elephant, fridge);

方法名put,加上兩個(gè)有意義的變量名elephant和fridge,已經(jīng)說(shuō)明了這是在干什么,語(yǔ)

義清晰的代碼不需要額外的注釋。

11.【參考】特殊注釋標(biāo)記,請(qǐng)注明標(biāo)記人與標(biāo)記時(shí)間。注意及時(shí)處理這些標(biāo)記,通過(guò)標(biāo)記掃描,

經(jīng)常清理此類標(biāo)記。線上故障有時(shí)候就是來(lái)源于這些標(biāo)記處的代碼。

1)待辦事宜(TODO):(標(biāo)記人,標(biāo)記時(shí)間,[預(yù)計(jì)處理時(shí)間])

表示需要實(shí)現(xiàn),但目前還未實(shí)現(xiàn)的功能。這實(shí)際上是一個(gè)Javadoc的標(biāo)簽,目前的Javadoc

還沒(méi)有實(shí)現(xiàn),但已經(jīng)被廣泛使用。只能應(yīng)用于類,接口和方法(因?yàn)樗且粋€(gè)Javadoc標(biāo)簽)。

2)錯(cuò)誤,不能工作(FIXME):(標(biāo)記人,標(biāo)記時(shí)間,[預(yù)計(jì)處理時(shí)間])

在注釋中用FIXME標(biāo)記某代碼是錯(cuò)誤的,而且不能工作,需要及時(shí)糾正的情況。

(九)其它

1.【強(qiáng)制】在使用正則表達(dá)式時(shí),利用好其預(yù)編譯功能,可以有效加快正則匹配速度。

說(shuō)明:不要在方法體內(nèi)定義:Pattern pattern=Pattern.compile(規(guī)則);

2.【強(qiáng)制】velocity調(diào)用POJO類的屬性時(shí),建議直接使用屬性名取值即可,模板引擎會(huì)自動(dòng)按

規(guī)范調(diào)用POJO的getXxx(),如果是boolean基本數(shù)據(jù)類型變量(boolean命名不需要加is

前綴),會(huì)自動(dòng)調(diào)用isXxx()方法。

說(shuō)明:注意如果是Boolean包裝類對(duì)象,優(yōu)先調(diào)用getXxx()的方法。

3.【強(qiáng)制】后臺(tái)輸送給頁(yè)面的變量必須加$!{var}——中間的感嘆號(hào)。

說(shuō)明:如果var=null或者不存在,那么${var}會(huì)直接顯示在頁(yè)面上。

4.【強(qiáng)制】注意Math.random()這個(gè)方法返回是double類型,注意取值的范圍0≤x<1(能夠

取到零值,注意除零異常),如果想獲取整數(shù)類型的隨機(jī)數(shù),不要將x放大10的若干倍然后

取整,直接使用Random對(duì)象的nextInt或者nextLong方法。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——18/34

5.【強(qiáng)制】獲取當(dāng)前毫秒數(shù)System.currentTimeMillis();而不是new Date().getTime();

說(shuō)明:如果想獲取更加精確的納秒級(jí)時(shí)間值,用System.nanoTime()。在JDK8中,針對(duì)統(tǒng)計(jì)

時(shí)間等場(chǎng)景,推薦使用Instant類。

6.【推薦】盡量不要在vm中加入變量聲明、邏輯運(yùn)算符,更不要在vm模板中加入任何復(fù)雜的邏

輯。

7.【推薦】 任何數(shù)據(jù)結(jié)構(gòu)的構(gòu)造或初始化,都應(yīng)指定大小,避免數(shù)據(jù)結(jié)構(gòu)無(wú)限增長(zhǎng)吃光內(nèi)存。

8.【推薦】對(duì)于“明確停止使用的代碼和配置”,如方法、變量、類、配置文件、動(dòng)態(tài)配置屬性

等要堅(jiān)決從程序中清理出去,避免造成過(guò)多垃圾。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——19/34

二、異常日志

(一)異常處理

1.【強(qiáng)制】不要捕獲Java類庫(kù)中定義的繼承自RuntimeException的運(yùn)行時(shí)異常類,如:

IndexOutOfBoundsException / NullPointerException,這類異常由程序員預(yù)檢查

來(lái)規(guī)避,保證程序健壯性。

正例:if(obj != null) {...}

反例:try { obj.method() } catch(NullPointerException e){...}

2.【強(qiáng)制】異常不要用來(lái)做流程控制,條件控制,因?yàn)楫惓5奶幚硇时葪l件分支低。

3.【強(qiáng)制】對(duì)大段代碼進(jìn)行try-catch,這是不負(fù)責(zé)任的表現(xiàn)。catch時(shí)請(qǐng)分清穩(wěn)定代碼和非穩(wěn)

定代碼,穩(wěn)定代碼指的是無(wú)論如何不會(huì)出錯(cuò)的代碼。對(duì)于非穩(wěn)定代碼的catch盡可能進(jìn)行區(qū)分

異常類型,再做對(duì)應(yīng)的異常處理。

4.【強(qiáng)制】捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請(qǐng)

將該異常拋給它的調(diào)用者。最外層的業(yè)務(wù)使用者,必須處理異常,將其轉(zhuǎn)化為用戶可以理解的

內(nèi)容。

5.【強(qiáng)制】有try塊放到了事務(wù)代碼中,catch異常后,如果需要回滾事務(wù),一定要注意手動(dòng)回

滾事務(wù)。

6.【強(qiáng)制】finally塊必須對(duì)資源對(duì)象、流對(duì)象進(jìn)行關(guān)閉,有異常也要做try-catch。

說(shuō)明:如果JDK7,可以使用try-with-resources方式。

7.【強(qiáng)制】不能在finally塊中使用return,finally塊中的return返回后方法結(jié)束執(zhí)行,不

會(huì)再執(zhí)行try塊中的return語(yǔ)句。

8.【強(qiáng)制】捕獲異常與拋異常,必須是完全匹配,或者捕獲異常是拋異常的父類。

說(shuō)明:如果預(yù)期對(duì)方拋的是繡球,實(shí)際接到的是鉛球,就會(huì)產(chǎn)生意外情況。

9.【推薦】方法的返回值可以為null,不強(qiáng)制返回空集合,或者空對(duì)象等,必須添加注釋充分

說(shuō)明什么情況下會(huì)返回null值。調(diào)用方需要進(jìn)行null判斷防止NPE問(wèn)題。

說(shuō)明:本規(guī)約明確防止NPE是調(diào)用者的責(zé)任。即使被調(diào)用方法返回空集合或者空對(duì)象,對(duì)調(diào)用

者來(lái)說(shuō),也并非高枕無(wú)憂,必須考慮到遠(yuǎn)程調(diào)用失敗,運(yùn)行時(shí)異常等場(chǎng)景返回null的情況。

10.【推薦】防止NPE,是程序員的基本修養(yǎng),注意NPE產(chǎn)生的場(chǎng)景:

1)返回類型為包裝數(shù)據(jù)類型,有可能是null,返回int值時(shí)注意判空。

反例:public int f(){return Integer對(duì)象};如果為null,自動(dòng)解箱拋NPE。

2)數(shù)據(jù)庫(kù)的查詢結(jié)果可能為null。

3)集合里的元素即使isNotEmpty,取出的數(shù)據(jù)元素也可能為null。

阿里巴巴Java開(kāi)發(fā)手冊(cè)

——禁止用于商業(yè)用途,違者必究——20/34

4)遠(yuǎn)程調(diào)用返回對(duì)象,一律要求進(jìn)行NPE判斷。

5)對(duì)于Session中獲取的數(shù)據(jù),建議NPE檢查,避免空指針。

6)級(jí)聯(lián)調(diào)用obj.getA().getB().getC();一連串調(diào)用,易產(chǎn)生NPE。

11.【推薦】在代碼中使用“拋異常”還是“返回錯(cuò)誤碼”,對(duì)于公司外的http/api開(kāi)放接口必須

使用“錯(cuò)誤碼”;而應(yīng)用內(nèi)部推薦異常拋出;跨應(yīng)用間RPC調(diào)用優(yōu)先考慮使用Result方式,封

裝isSuccess、“錯(cuò)誤碼”、“錯(cuò)誤簡(jiǎn)短信息”。

說(shuō)明:關(guān)于RPC方法返回方式使用Result方式的理由:

1)使用拋異常返回方式,調(diào)用方如果沒(méi)有捕獲到就會(huì)產(chǎn)生運(yùn)行時(shí)錯(cuò)誤。

2)如果不加棧信息,只是new自定義異常,加入自己的理解的error message,對(duì)于調(diào)用

端解決問(wèn)題的幫助不會(huì)太多。如果加了棧信息,在頻繁調(diào)用出錯(cuò)的情況下,數(shù)據(jù)序列化和傳輸

的性能損耗也是問(wèn)題。

12.【推薦】定義時(shí)區(qū)分unchecked/checked異常,避免直接使用RuntimeException拋出,

更不允許拋出Exception或者Throwable,應(yīng)使用有業(yè)務(wù)含義的自定義異常。推薦業(yè)界已定義

過(guò)的自定義異常,如:DAOException/ServiceException等。

13.【參考】避免出現(xiàn)重復(fù)的代碼(Don’t Repeat Yourself),即DRY原則。

說(shuō)明:隨意復(fù)制和粘貼代碼,必然會(huì)導(dǎo)致代碼的重復(fù),在以后需要修改時(shí),需要修改所有的副

本,容易遺漏。必要時(shí)抽取共性方法,或者抽象公共類,甚至是共用模塊。

正例:一個(gè)類中有多個(gè)public方法,都需要進(jìn)行數(shù)行相同的參數(shù)校驗(yàn)操作,這個(gè)時(shí)候請(qǐng)抽取:

private boolean checkParam(DTO dto){...}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容