免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Java編程規(guī)范

本文引用阿里Java開發(fā)手冊。
GitHub閱讀地址:

目錄

編程規(guī)約

命名規(guī)約

1、【強(qiáng)制】 所有編程相關(guān)命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結(jié)束

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

2、【強(qiáng)制】 所有編程相關(guān)的命名嚴(yán)禁使用拼音與英語混合的方式,更不允許直接使用中的方式。

  說明: 正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。注意,即純拼音的命名方式也要避免采用?! 》蠢?DaZhePromotion [打折] / getPingfenByName() [評分] / int 變量 = 3;  正例: ali / alibaba / taobao / cainiao / aliyun / youku / hangzhou 等國際通用的名稱,可視為英文。
  • 1
  • 2
  • 3
  • 4
  • 5

3、【強(qiáng)制】 類名使用 UpperCamelCase 風(fēng)格,必須遵從駝峰形式,但以下情形例外:(領(lǐng)域模型的相關(guān)命名) DO / DTO / VO / DAO 等。

  正例: MarcoPolo / UserDO / XmlService / TcpUdpDeal / TaPromotion  反例: macroPolo / UserDo / XMLService / TCPUDPDeal / TAPromotion
  • 1
  • 2
  • 3

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

  正例: localValue / getHttpMessage() / inputUserId
  • 1

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

  正例: MAX_STOCK_COUNT  反例: MAX_COUNT
  • 1
  • 2
  • 3

6、【強(qiáng)制】 抽象類命名使用 AbstractBase 開頭;異常類命名使用 Exception 結(jié)尾;測試類命名以它要測試的類的名稱開始,以 Test 結(jié)尾。

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

  反例: 請勿使用 String args[] 的方式來定義
  • 1

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

  反例: 定義為基本數(shù)據(jù)類型 boolean isSuccess;的屬性,它的方法也是 isSuccess(), RPC框架在反向解析的時候, “ 以為” 對應(yīng)的屬性名稱是 success,導(dǎo)致屬性獲取不到,進(jìn)而拋出異常。
  • 1

9、【強(qiáng)制】 包名統(tǒng)一使用小寫,點(diǎn)分隔符之間有且僅有一個自然語義的英語單詞。包名統(tǒng)一使用單數(shù)形式,但是類名如果有復(fù)數(shù)含義,類名可以使用復(fù)數(shù)形式。

  正例: 應(yīng)用工具類包名為 com.alibaba.mpp.util、類名為 MessageUtils (此規(guī)則參考 spring的框架結(jié)構(gòu))
  • 1

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

  反例: <某業(yè)務(wù)代碼>AbstractClass“ 縮寫” 命名成 AbsClass; condition“ 縮寫” 命名成condi,此類隨意縮寫嚴(yán)重降低了代碼的可閱讀性。
  • 1

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

  說明: 將設(shè)計(jì)模式體現(xiàn)在名字中,有利于閱讀者快速理解架構(gòu)設(shè)計(jì)思想?! ≌?public class OrderFactory; public class LoginProxy; public class ResourceObserver;
  • 1
  • 2
  • 3

12、【推薦】 接口類中的方法和屬性不要加任何修飾符號( public 也不要加),保持代碼的簡潔性,并加上有效的 javadoc 注釋。盡量不要在接口里定義變量,如果一定要定義變量,肯定是與接口方法相關(guān),并且是整個應(yīng)用的基礎(chǔ)常量。

  正例: 接口方法簽名: void f(); 接口基礎(chǔ)常量表示: String COMPANY = 'alibaba';  反例: 接口方法定義: public abstract void f();  說明: JDK8 中接口允許有默認(rèn)實(shí)現(xiàn),那么這個 default 方法,是對所有實(shí)現(xiàn)類都有價值的默認(rèn)實(shí)現(xiàn)。
  • 1
  • 2
  • 3
  • 4
  • 5

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

 ?。保緩?qiáng)制】 對于 Service 和 DAO 類,基于 SOA 的理念,暴露出來的服務(wù)一定是接口,內(nèi)部的實(shí)現(xiàn)類用 Impl 的后綴與接口區(qū)別。正例: CacheServiceImpl 實(shí)現(xiàn) CacheService 接口?! 。玻就扑]】 如果是形容能力的接口名稱,取對應(yīng)的形容詞做接口名(通常是–able 的形式)。正例: AbstractTranslator 實(shí)現(xiàn) Translatable。
  • 1
  • 2
  • 3

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

  說明: 枚舉其實(shí)就是特殊的常量類,且構(gòu)造方法被默認(rèn)強(qiáng)制是私有?! ≌?枚舉名字: DealStatusEnum;成員名稱: SUCCESS / UNKOWN_REASON。
  • 1
  • 2
  • 3

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

  A) Service/DAO 層方法命名規(guī)約    1) 獲取單個對象的方法用 get 做前綴?!   ?) 獲取多個對象的方法用 list 做前綴?!   ?) 獲取統(tǒng)計(jì)值的方法用 count 做前綴。    4) 插入的方法用 save(推薦)或 insert 做前綴?!   ?span>5) 刪除的方法用 remove(推薦)或 delete 做前綴?!   ?span>6) 修改的方法用 update 做前綴?! ) 領(lǐng)域模型命名規(guī)約    1) 數(shù)據(jù)對象: xxxDO, xxx 即為數(shù)據(jù)表名?!   ?span>2) 數(shù)據(jù)傳輸對象: xxxDTO, xxx 為業(yè)務(wù)領(lǐng)域相關(guān)的名稱?!   ?span>3) 展示對象: xxxVO, xxx 一般為網(wǎng)頁名稱。    4) POJO 是 DO/DTO/BO/VO 的統(tǒng)稱,禁止命名成 xxxPOJO。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

常量定義

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

  反例: String key='Id#taobao_' tradeId; cache.put(key, value);
  • 1

2、【強(qiáng)制】 long 或者 Long 初始賦值時,必須使用大寫的 L,不能是小寫的 l,小寫容易跟數(shù)字 1混淆,造成誤解。

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

3、【推薦】 不要使用一個常量類維護(hù)所有常量,應(yīng)該按常量功能進(jìn)行歸類,分開維護(hù)。如:緩存相關(guān)的常量放在類: CacheConsts 下;系統(tǒng)配置相關(guān)的常量放在類: ConfigConsts 下。

  說明: 大而全的常量類,非得 ctrl f 才定位到修改的常量,不利于理解,也不利于維護(hù)。
  • 1

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

  1) 跨應(yīng)用共享常量:放置在二方庫中,通常是 client.jar 中的 const 目錄下?! ?span>2) 應(yīng)用內(nèi)共享常量:放置在一方庫的 modules 中的 const 目錄下。  反例: 易懂變量也要統(tǒng)一定義成應(yīng)用內(nèi)共享常量,兩位攻城師在兩個類中分別定義了表示“ 是” 的變量:  類 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)生線上問題。    3) 子工程內(nèi)部共享常量:即在當(dāng)前子工程的 const 目錄下?! ?span>4) 包內(nèi)共享常量:即在當(dāng)前包下單獨(dú)的 const 目錄下?! ?span>5) 類內(nèi)共享常量:直接在類內(nèi)部 private static final 定義。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5、【推薦】 如果變量值僅在一個范圍內(nèi)變化用 Enum 類。如果還帶有名稱之外的延伸屬性,必須使用 Enum 類,下面正例中的數(shù)字就是延伸信息,表示星期幾。

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

格式規(guī)范

1、【強(qiáng)制】 大括號的使用約定。如果是大括號內(nèi)為空,則簡潔地寫成{}即可,不需要換行; 如果是非空代碼塊則:

  1) 左大括號前不換行?! ?span>2) 左大括號后換行?! ?span>3) 右大括號前換行?! ?span>4) 右大括號后還有 else 等代碼則不換行; 表示終止右大括號后必須換行。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、【強(qiáng)制】 左括號和后一個字符之間不出現(xiàn)空格; 同樣,右括號和前一個字符之間也不出現(xiàn)空格。詳見第 5 條下方正例提示。

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

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

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

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

  說明: 如果使用 tab 縮進(jìn),必須設(shè)置 1tab4 個空格。 IDEA 設(shè)置 tab4 個空格時,請勿勾選 Use tab character;而在 eclipse 中,必須勾選 insert spaces for tabs。
  • 1
  正例: ( 涉及 1-5 點(diǎn))  public static void main(String args[]) {   // 縮進(jìn) 4 個空格    String say = 'hello';   // 運(yùn)算符的左右必須有一個空格   int flag = 0;   // 關(guān)鍵詞 if 與括號之間必須有一個空格,括號內(nèi)的 f 與左括號, 0 與右括號不需要空格   if (flag == 0) {   System.out.println(say);   }   // 左大括號前加空格且不換行;左大括號后換行   if (flag == 1) {   System.out.println('world');   // 右大括號前換行,右大括號后有 else,不用換行   } else {   System.out.println('ok');   // 在右大括號后直接結(jié)束,則必須換行   }  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

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

  1) 第二行相對第一行縮進(jìn) 4 個空格,從第三行開始,不再繼續(xù)縮進(jìn),參考示例?! ?) 運(yùn)算符與下文一起換行?! ?) 方法調(diào)用的點(diǎn)符號與下文一起換行。  4) 在多個參數(shù)超長,逗號后進(jìn)行換行。  5) 在括號前不要換行,見反例。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  正例:  StringBuffer sb = new StringBuffer();    //超過 120 個字符的情況下,換行縮進(jìn) 4 個空格,并且方法前的點(diǎn)符號一起換行    sb.append('zi').append('xin')...      .append('huang')...      .append('huang')...      .append('huang');  反例:  StringBuffer sb = new StringBuffer();  //超過 120 個字符的情況下,不要在括號前換行  sb.append('zi').append('xin')...append  ('huang');  //參數(shù)很多的方法調(diào)用可能超過 120 個字符, 不要在逗號前換行  method(args1, args2, args3, ...    , argsX);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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

  正例: 下例中實(shí)參的'a',后邊必須要有一個空格。  method('a', 'b', 'c');
  • 1
  • 2
  • 3

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

9、【推薦】 沒有必要增加若干空格來使某一行的字符與上一行的相應(yīng)字符對齊。

  正例:   int a = 3;  long b = 4L;  float c = 5F;  StringBuffer sb = new StringBuffer();  說明: 增加 sb 這個變量,如果需要對齊,則給 a、 b、 c 都要增加幾個空格,在變量比較多的情況下,是一種累贅的事情。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

10、【推薦】 方法體內(nèi)的執(zhí)行語句組、變量的定義語句組、不同的業(yè)務(wù)邏輯之間或者不同的語義之間插入一個空行。相同業(yè)務(wù)邏輯和語義之間不需要插入空行。

  說明: 沒有必要插入多行空格進(jìn)行隔開。
  • 1

面向?qū)ο缶幊桃?guī)約

1、【強(qiáng)制】 避免通過一個類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法,無謂增加編譯器解析成本,直接用類名來訪問即可。

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

  反例: getObject()get0bject()的問題。一個是字母的 O,一個是數(shù)字的 0,加@Override可以準(zhǔn)確判斷是否覆蓋成功。另外,如果在抽象類中對方法簽名進(jìn)行修改,其實(shí)現(xiàn)類會馬上編譯報錯。
  • 1

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

  說明: 可變參數(shù)必須放置在參數(shù)列表的最后。(提倡同學(xué)們盡量不用可變參數(shù)編程)  正例: public User getUsers(String type, Integer... ids)
  • 1
  • 2
  • 3

4、【強(qiáng)制】 對外暴露的接口簽名,原則上不允許修改方法簽名,避免對接口調(diào)用方產(chǎn)生影響。接口過時必須加 @Deprecated 注解,并清晰地說明采用的新接口或者新服務(wù)是什么。

5、【強(qiáng)制】 不能使用過時的類或方法。

  說明: java.net.URLDecoder 中的方法 decode(String encodeStr) 這個方法已經(jīng)過時,應(yīng)該使用雙參數(shù) decode(String source, String encode)。接口提供方既然明確是過時接口,那么有義務(wù)同時提供新的接口; 作為調(diào)用方來說,有義務(wù)去考證過時方法的新實(shí)現(xiàn)是什么。
  • 1

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

  正例: 'test'.equals(object);  反例: object.equals('test');  說明: 推薦使用 java.util.Objects#equals ( JDK7 引入的工具類)
  • 1
  • 2
  • 3
  • 4
  • 5

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

  說明: 對于 Integer var=?-128127 之間的賦值, Integer 對象是在IntegerCache.cache 產(chǎn)生,會復(fù)用已有對象,這個區(qū)間內(nèi)的 Integer 值可以直接使用==進(jìn)行判斷,但是這個區(qū)間之外的所有數(shù)據(jù),都會在堆上產(chǎn)生,并不會復(fù)用已有對象,這是一個大坑,推薦使用 equals 方法進(jìn)行判斷。
  • 1

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

  1) 所有的 POJO 類屬性必須使用包裝數(shù)據(jù)類型?! ?) RPC 方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型?! ?) 所有的局部變量【 推薦】 使用基本數(shù)據(jù)類型。
  • 1
  • 2
  • 3
  • 4
  • 5
  說明: POJO 類屬性沒有初值是提醒使用者在需要使用時,必須自己顯式地進(jìn)行賦值,任何NPE問題,或者入庫檢查,都由使用者來保證?! ≌?數(shù)據(jù)庫的查詢結(jié)果可能是 null,因?yàn)樽詣硬鹣?,用基本?shù)據(jù)類型接收有 NPE 風(fēng)險?! 》蠢?比如顯示成交總額漲跌情況,即正負(fù) x%, x 為基本數(shù)據(jù)類型,調(diào)用的 RPC 服務(wù),調(diào)用不成功時,返回的是默認(rèn)值,頁面顯示: 0%,這是不合理的,應(yīng)該顯示成中劃線-。所以包裝數(shù)據(jù)類型的 null 值,能夠表示額外的信息, 如:遠(yuǎn)程調(diào)用失敗,異常退出。
  • 1
  • 2
  • 3
  • 4
  • 5

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

  反例: POJO 類的 gmtCreate 默認(rèn)值為 new Date();但是這個屬性在數(shù)據(jù)提取時并沒有置入具體值,在更新其它字段時又附帶更新了此字段,導(dǎo)致創(chuàng)建時間被修改成當(dāng)前時間。
  • 1

10、【強(qiáng)制】 序列化類新增屬性時,請不要修改 serialVersionUID 字段,避免反序列失??; 如果完全不兼容升級,避免反序列化混亂,那么請修改 serialVersionUID 值。

  說明: 注意 serialVersionUID 不一致會拋出序列化運(yùn)行時異常。
  • 1

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

12、【強(qiáng)制】 POJO 類必須寫 toString 方法。使用 IDE 的中工具: source> generate toString時,如果繼承了另一個 POJO 類,注意在前面加一下 super.toString。

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

13、【推薦】 使用索引訪問用 String 的 split 方法得到的數(shù)組時,需做最后一個分隔符后有無內(nèi)容的檢查,否則會有拋 IndexOutOfBoundsException 的風(fēng)險。

  說明:  String str = 'a,b,c,,';  String[] ary = str.split(',');  //預(yù)期大于 3,結(jié)果是 3  System.out.println(ary.length);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

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

  說明: 公有方法是類的調(diào)用者和維護(hù)者最關(guān)心的方法,首屏展示最好; 保護(hù)方法雖然只是子類關(guān)心,也可能是“模板設(shè)計(jì)模式”下的核心方法; 而私有方法外部一般不需要特別關(guān)心,是一個黑盒實(shí)現(xiàn); 因?yàn)榉椒ㄐ畔r值較低,所有 Service 和 DAO 的 getter/setter 方法放在類體最后。
  • 1

16、【推薦】 setter 方法中,參數(shù)名稱與類成員變量名稱一致, this.成員名=參數(shù)名。在getter/setter 方法中,盡量不要增加業(yè)務(wù)邏輯,增加排查問題的難度。

  反例:  public Integer getData(){    if(true) {      return data 100;    } else {      return data - 100;    }  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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';  }  說明: 反編譯出的字節(jié)碼文件顯示每次循環(huán)都會 new 出一個 StringBuilder 對象,然后進(jìn)行append 操作,最后通過 toString 方法返回 String 對象,造成內(nèi)存資源浪費(fèi)?!?/code>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

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

  1) 不需要重新賦值的變量,包括類屬性、局部變量?! ?span>2) 對象參數(shù)前加 final,表示不允許修改引用的指向。  3) 類方法確定不允許被重寫。
  • 1
  • 2
  • 3
  • 4
  • 5

19、【推薦】 慎用 Object 的 clone 方法來拷貝對象。

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

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

  1) 如果不允許外部直接通過 new 來創(chuàng)建對象,那么構(gòu)造方法必須是 private。  2) 工具類不允許有 publicdefault 構(gòu)造方法?! ?) 類非 static 成員變量并且與子類共享,必須是 protected?! ?) 類非 static 成員變量并且僅在本類使用,必須是 private。  5) 類 static 成員變量如果僅在本類使用,必須是 private。  6) 若是 static 成員變量,必須考慮是否為 final?! ?) 類成員方法只供類內(nèi)部調(diào)用,必須是 private。  8) 類成員方法只對繼承類公開,那么限制為 protected?! ≌f明: 任何類、方法、參數(shù)、變量,嚴(yán)控訪問范圍。過寬泛的訪問范圍,不利于模塊解耦。思考:如果是一個 private 的方法,想刪除就刪除,可是一個 public 的 Service 方法,或者一個 public 的成員變量,刪除一下,不得手心冒點(diǎn)汗嗎?變量像自己的小孩,盡量在自己的視線內(nèi),變量作用域太大,如果無限制的到處跑,那么你會擔(dān)心的。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

集合處理

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

  1) 只要重寫 equals,就必須重寫 hashCode?! ?span>2) 因?yàn)?Set 存儲的是不重復(fù)的對象,依據(jù) hashCode 和 equals 進(jìn)行判斷,所以 Set 存儲的對象必須重寫這兩個方法?! ?span>3) 如果自定義對象做為 Map 的鍵,那么必須重寫 hashCode 和 equals?! ≌?String 重寫了 hashCode 和 equals 方法,所以我們可以非常愉快地使用 String 對象作為 key 來使用。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、【強(qiáng)制】 ArrayList 的 subList 結(jié)果不可強(qiáng)轉(zhuǎn)成 ArrayList,否則會拋出 ClassCastException 異常: java.util.RandomAccessSubList cannot be cast to java.util.ArrayList ;

  說明: subList 返回的是 ArrayList 的內(nèi)部類 SubList,并不是 ArrayList ,而是ArrayList 的一個視圖,對于 SubList 子列表的所有操作最終會反映到原列表上。
  • 1

3、【強(qiáng)制】 在 subList 場景中, 高度注意對原集合元素個數(shù)的修改,會導(dǎo)致子列表的遍歷、增加、刪除均產(chǎn)生 ConcurrentModificationException 異常。

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

  反例: 直接使用 toArray 無參方法存在問題,此方法返回值只能是 Object[]類,若強(qiáng)轉(zhuǎn)其它類型數(shù)組將出現(xiàn) ClassCastException 錯誤?! ≌骸  ?span>List<String> list = new ArrayList<String>(2);  list.add('guan');  list.add('bao');  String[] array = new String[list.size()];  array = list.toArray(array);  說明: 使用 toArray 帶參方法,入?yún)⒎峙涞臄?shù)組空間不夠大時, toArray 方法內(nèi)部將重新分配內(nèi)存空間,并返回新數(shù)組地址; 如果數(shù)組元素大于實(shí)際所需,下標(biāo)為[ list.size() ]的數(shù)組元素將被置為 null,其它數(shù)組元素保持原值,因此最好將方法入?yún)?shù)組大小定義與集合元素個數(shù)一致。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

5、【強(qiáng)制】 使用工具類 Arrays.asList() 把數(shù)組轉(zhuǎn)換成集合時,不能使用其修改集合相關(guān)的方法,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。

  說明: asList 的返回對象是一個 Arrays 內(nèi)部類,并沒有實(shí)現(xiàn)集合的修改方法。Arrays.asList體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺的數(shù)據(jù)仍是數(shù)組。  String[] str = new String[] { 'a', 'b' };  List list = Arrays.asList(str);  第一種情況: list.add('c'); 運(yùn)行時異常?! 〉诙N情況: str[0]= 'gujin'; 那么 list.get(0)也會隨之修改。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

6、【強(qiáng)制】 泛型通配符

  說明: 蘋果裝箱后返回一個<? extends Fruits>對象,此對象就不能往里加任何水果,包括蘋果。
  • 1

7、【強(qiáng)制】 不要在 foreach 循環(huán)里進(jìn)行元素的 remove/add 操作。 remove 元素請使用 Iterator方式,如果并發(fā)操作,需要對 Iterator 對象加鎖。

  反例:  List<String> a = new ArrayList<String>();  a.add('1');  a.add('2');  for (String temp : a) {    if('1'.equals(temp)){      a.remove(temp);    }  }  說明: 以上代碼的執(zhí)行結(jié)果肯定會出乎大家的意料,那么試一下把“1”換成“2”,會是同樣的結(jié)果嗎?  正例:  Iterator<String> it = a.iterator();  while(it.hasNext()){    String temp = it.next();    if(刪除元素的條件){      it.remove();    }  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

8、【強(qiáng)制】 在 JDK7 版本以上, Comparator 要滿足自反性,傳遞性,對稱性,不然 Arrays.sort,Collections.sort 會報 IllegalArgumentException 異常。

  說明:  1) 自反性: x, y 的比較結(jié)果和 y, x 的比較結(jié)果相反。  2) 傳遞性: x>y,y>z,則 x>z。  3) 對稱性: x=y,則 x,z 比較結(jié)果和 y, z 比較結(jié)果相同。  反例: 下例中沒有處理相等的情況,實(shí)際使用中可能會出現(xiàn)異常:  new Comparator<Student>() {    @Override    public int compare(Student o1, Student o2) {      return o1.getId() > o2.getId() ? 1 : -1;    }  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

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

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

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

  說明: keySet 其實(shí)是遍歷了 2 次,一次是轉(zhuǎn)為 Iterator 對象,另一次是從 hashMap 中取出key 所對應(yīng)的 value。而 entrySet 只是遍歷了一次就把 key 和 value 都放到了 entry 中,效率更高。如果是 JDK8,使用 Map.foreach 方法?!   ≌?values()返回的是 V 值集合,是一個 list 集合對象; keySet()返回的是 K 值集合,是一個 Set 集合對象; entrySet()返回的是 K-V 值組合集合。
  • 1
  • 2
  • 3

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

集合類 Key Value Super 說明
Hashtable 不允許為null 不允許為null Dictionary 線程安全
ConcurrentHashMap 不允許為null 不允許為null AbstractMap 分段鎖技術(shù)
TreeMap 不允許為null 允許為null AbstractMap 分段鎖技術(shù)
HashMap 允許為null 允許為null AbstractMap 線程不安全

  反例: 由于 HashMap 的干擾,很多人認(rèn)為 ConcurrentHashMap 是可以置入 null 值,注意存儲null 值時會拋出 NPE 異常。

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

  說明: 穩(wěn)定性指集合每次遍歷的元素次序是一定的。有序性是指遍歷的結(jié)果是按某種比較規(guī)則依次排列的。如: ArrayList 是 order/unsort; HashMap 是 unorder/unsort; TreeSet 是order/sort。
  • 1

13、【參考】 利用 Set 元素唯一的特性,可以快速對一個集合進(jìn)行去重操作,避免使用 List 的contains 方法進(jìn)行遍歷、對比、 去重操作。

并發(fā)處理

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

  說明: 資源驅(qū)動類、工具類、單例工廠類都需要注意。
  • 1

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

正例:  public class TimerTaskThread extends Thread {    public TimerTaskThread(){    super.setName('TimerTaskThread'); ...  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

  說明: 使用線程池的好處是減少在創(chuàng)建和銷毀線程上所花的時間以及系統(tǒng)資源的開銷,解決資源不足的問題。如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者“過度切換”的問題。
  • 1

4、【強(qiáng)制】 線程池不允許使用 Executors 去創(chuàng)建,而是通過 ThreadPoolExecutor 的方式,這樣的處理方式讓寫的同學(xué)更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源耗盡的風(fēng)險。

  說明: Executors 返回的線程池對象的弊端如下:    1)FixedThreadPool 和 SingleThreadPool:允許的請求隊(duì)列長度為 Integer.MAX_VALUE,可能會堆積大量的請求,從而導(dǎo)致 OOM?!   ?span>2)CachedThreadPool 和 ScheduledThreadPool:允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE, 可能會創(chuàng)建大量的線程,從而導(dǎo)致 OOM。
  • 1
  • 2
  • 3
  • 4
  • 5

5、【強(qiáng)制】 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 的應(yīng)用,可以使用 Instant 代替 Date, LocalDateTime 代替 Calendar,DateTimeFormatter代替Simpledateformatter,官方給出的解釋:simple beautiful strongimmutable thread-safe。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

6、【強(qiáng)制】 高并發(fā)時,同步調(diào)用應(yīng)該去考量鎖的性能損耗。能用無鎖數(shù)據(jù)結(jié)構(gòu),就不要用鎖; 能鎖區(qū)塊,就不要鎖整個方法體; 能用對象鎖,就不要用類鎖。

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

  說明: 線程一需要對表 A、 B、 C 依次全部加鎖后才可以進(jìn)行更新操作,那么線程二的加鎖順序也必須是 A、 B、 C,否則可能出現(xiàn)死鎖。
  • 1

8、【強(qiáng)制】 并發(fā)修改同一記錄時,避免更新丟失,要么在應(yīng)用層加鎖,要么在緩存加鎖,要么在數(shù)據(jù)庫層使用樂觀鎖,使用 version 作為更新依據(jù)。

  說明: 如果每次訪問沖突概率小于 20%,推薦使用樂觀鎖,否則使用悲觀鎖。樂觀鎖的重試次數(shù)不得小于 3 次。
  • 1

9、【強(qiáng)制】 多線程并行處理定時任務(wù)時, Timer 運(yùn)行多個 TimeTask 時,只要其中之一沒有捕獲拋出的異常,其它任務(wù)便會自動終止運(yùn)行,使用 ScheduledExecutorService 則沒有這個問題。

10、【推薦】 使用 CountDownLatch 進(jìn)行異步轉(zhuǎn)同步操作,每個線程退出前必須調(diào)用 countDown方法,線程執(zhí)行代碼注意 catch 異常,確保 countDown 方法可以執(zhí)行,避免主線程無法執(zhí)行至 countDown 方法,直到超時才返回結(jié)果。

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

11、【推薦】 避免 Random 實(shí)例被多線程使用,雖然共享該實(shí)例是線程安全的,但會因競爭同一seed 導(dǎo)致的性能下降。

說明: Random 實(shí)例包括 java.util.Random 的實(shí)例或者 Math.random()實(shí)例。正例: 在 JDK7 之后,可以直接使用 API ThreadLocalRandom,在 JDK7 之前,可以做到每個線程一個實(shí)例。
  • 1

12、【推薦】 通過雙重檢查鎖( double-checked locking)( 在并發(fā)場景) 實(shí)現(xiàn)延遲初始化的優(yōu)化問題隱患(可參考 The “Double-Checked Locking is Broken” Declaration),推薦問題解決方案中較為簡單一種( 適用于 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...  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

13、【參考】 volatile 解決多線程內(nèi)存不可見問題。對于一寫多讀,是可以解決變量同步問題,但是如果多寫,同樣無法解決線程安全問題。如果是 count 操作,使用如下類實(shí)現(xiàn):AtomicInteger count = new AtomicInteger(); count.addAndGet(1); 如果是 JDK8,推薦使用 LongAdder 對象,比 AtomicLong 性能更好( 減少樂觀鎖的重試次數(shù)) 。

14、【參考】 HashMap 在容量不夠進(jìn)行 resize 時由于高并發(fā)可能出現(xiàn)死鏈,導(dǎo)致 CPU 飆升,在開發(fā)過程中注意規(guī)避此風(fēng)險。

15、【參考】 ThreadLocal 無法解決共享對象的更新問題, ThreadLocal 對象建議使用 static修飾。這個變量是針對一個線程內(nèi)所有操作共有的,所以設(shè)置為靜態(tài)變量,所有此類實(shí)例共享此靜態(tài)變量 ,也就是說在類第一次被使用時裝載,只分配一塊存儲空間,所有此類的對象(只要是這個線程內(nèi)定義的)都可以操控這個變量。

控制語句

1、【強(qiáng)制】 在一個 switch 塊內(nèi),每個 case 要么通過 break/return 等來終止,要么注釋說明程序?qū)⒗^續(xù)執(zhí)行到哪一個 case 為止; 在一個 switch 塊內(nèi),都必須包含一個 default 語句并且放在最后,即使它什么代碼也沒有。

2、【強(qiáng)制】 在 if/else/for/while/do 語句中必須使用大括號,即使只有一行代碼,避免使用下面的形式: if (condition) statements;

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

  if(condition){    ...    return obj;  }  // 接著寫 else 的業(yè)務(wù)邏輯代碼;  說明: 如果非得使用 if()...else if()...else...方式表達(dá)邏輯,【強(qiáng)制】請勿超過 3 層,超過請使用狀態(tài)設(shè)計(jì)模式?! ≌?邏輯上超過 3 層的 if-else 代碼可以使用衛(wèi)語句,或者狀態(tài)模式來實(shí)現(xiàn)。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

4、【推薦】 除常用方法(如 getXxx/isXxx)等外,不要在條件判斷中執(zhí)行其它復(fù)雜的語句,將復(fù)雜邏輯判斷的結(jié)果賦值給一個有意義的布爾變量名,以提高可讀性。

  說明: 很多 if 語句內(nèi)的邏輯相當(dāng)復(fù)雜,閱讀者需要分析條件表達(dá)式的最終結(jié)果,才能明確什么樣的條件執(zhí)行什么樣的語句,那么,如果閱讀者分析邏輯表達(dá)式錯誤呢?  正例:  //偽代碼如下  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
  • 14
  • 15

5、【推薦】 循環(huán)體中的語句要考量性能,以下操作盡量移至循環(huán)體外處理,如定義對象、變量、獲取數(shù)據(jù)庫連接,進(jìn)行不必要的 try-catch 操作( 這個 try-catch 是否可以移至循環(huán)體外) 。

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

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

  1) 調(diào)用頻次低的方法?! ?) 執(zhí)行時間開銷很大的方法,參數(shù)校驗(yàn)時間幾乎可以忽略不計(jì),但如果因?yàn)閰?shù)錯誤導(dǎo)致中間執(zhí)行回退,或者錯誤,那得不償失?! ?) 需要極高穩(wěn)定性和可用性的方法?! ?) 對外提供的開放接口,不管是 RPC/API/HTTP 接口?! ?) 敏感權(quán)限入口。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

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

  1) 極有可能被循環(huán)調(diào)用的方法,不建議對參數(shù)進(jìn)行校驗(yàn)。但在方法說明里必須注明外部參數(shù)檢查?! ?span>2) 底層的方法調(diào)用頻度都比較高,一般不校驗(yàn)。畢竟是像純凈水過濾的最后一道,參數(shù)錯誤不太可能到底層才會暴露問題。一般 DAO 層與 Service 層都在同一個應(yīng)用中,部署在同一臺服務(wù)器中,所以 DAO 的參數(shù)校驗(yàn),可以省略?! ?span>3) 被聲明成 private 只會被自己代碼所調(diào)用的方法,如果能夠確定調(diào)用方法的代碼傳入?yún)?shù)已經(jīng)做過檢查或者肯定不會有問題,此時可以不校驗(yàn)參數(shù)。
  • 1
  • 2
  • 3
  • 4
  • 5

注釋規(guī)約

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

  說明: 在 IDE 編輯窗口中, Javadoc 方式會提示相關(guān)注釋,生成 Javadoc 可以正確輸出相應(yīng)注釋; 在 IDE 中,工程調(diào)用方法時,不進(jìn)入方法即可懸浮提示方法、參數(shù)、返回值的意義,提高閱讀效率。
  • 1

2、【強(qiáng)制】 所有的抽象方法( 包括接口中的方法) 必須要用 Javadoc 注釋、除了返回值、參數(shù)、異常說明外,還必須指出該方法做什么事情,實(shí)現(xiàn)什么功能。

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

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

4、【強(qiáng)制】 方法內(nèi)部單行注釋,在被注釋語句上方另起一行,使用//注釋。方法內(nèi)部多行注釋使用/* */注釋,注意與代碼對齊。

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

6、【推薦】 與其“半吊子”英文來注釋,不如用中文注釋把問題說清楚。專有名詞與關(guān)鍵字保持英文原文即可。

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

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

  說明: 代碼與注釋更新不同步,就像路網(wǎng)與導(dǎo)航軟件更新不同步一樣,如果導(dǎo)航軟件嚴(yán)重滯后,就失去了導(dǎo)航的意義。
  • 1

8、【參考】 注釋掉的代碼盡量要配合說明,而不是簡單的注釋掉。

  說明: 代碼被注釋掉有兩種可能性:     1) 后續(xù)會恢復(fù)此段代碼邏輯?!   ?) 永久不用。前者如果沒有備注信息,難以知曉注釋動機(jī)。后者建議直接刪掉( 代碼倉庫保存了歷史代碼) 。
  • 1
  • 2
  • 3
  • 4
  • 5

9、【參考】 對于注釋的要求:第一、能夠準(zhǔn)確反應(yīng)設(shè)計(jì)思想和代碼邏輯; 第二、能夠描述業(yè)務(wù)含義,使別的程序員能夠迅速了解到代碼背后的信息。完全沒有注釋的大段代碼對于閱讀者形同天書,注釋是給自己看的,即使隔很長時間,也能清晰理解當(dāng)時的思路; 注釋也是給繼任者看的,使其能夠快速接替自己的工作。

10、【參考】 好的命名、代碼結(jié)構(gòu)是自解釋的,注釋力求精簡準(zhǔn)確、表達(dá)到位。避免出現(xiàn)注釋的一個極端:過多過濫的注釋,代碼的邏輯一旦修改,修改注釋是相當(dāng)大的負(fù)擔(dān)。

  反例:  // put elephant into fridge  put(elephant, fridge);  方法名 put,加上兩個有意義的變量名 elephant 和 fridge,已經(jīng)說明了這是在干什么,語義清晰的代碼不需要額外的注釋。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

11、【參考】 特殊注釋標(biāo)記,請注明標(biāo)記人與標(biāo)記時間。注意及時處理這些標(biāo)記,通過標(biāo)記掃描,經(jīng)常清理此類標(biāo)記。線上故障有時候就是來源于這些標(biāo)記處的代碼。

  1)待辦事宜( TODO ) :( 標(biāo)記人,標(biāo)記時間, [預(yù)計(jì)處理時間] )表示需要實(shí)現(xiàn),但目前還未實(shí)現(xiàn)的功能。這實(shí)際上是一個 Javadoc 的標(biāo)簽,目前的 Javadoc還沒有實(shí)現(xiàn),但已經(jīng)被廣泛使用。只能應(yīng)用于類,接口和方法(為它是一個 Javadoc 標(biāo)簽) ?! ?)錯誤,不能工作( FIXME) :( 標(biāo)記人,標(biāo)記時間, [預(yù)計(jì)處理時間])在注釋中用 FIXME 標(biāo)記某代碼是錯誤的,而且不能工作,需要及時糾正的情況。
  • 1
  • 2
  • 3

其他

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

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

2、【強(qiáng)制】 velocity 調(diào)用 POJO 類的屬性時,建議直接使用屬性名取值即可,模板引擎會自動按規(guī)范調(diào)用 POJO 的 getXxx(),如果是 boolean 基本數(shù)據(jù)類型變量( boolean 命名不需要加 i前綴 ),會自動調(diào)用 isXxx()方法。

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

3、【強(qiáng)制】 后臺輸送給頁面的變量必須加$!{var}——中間的感嘆號。

  說明: 如果 var = null 或者不存在,那么${var}會直接顯示在頁面上。
  • 1

4、【強(qiáng)制】 注意 Math.random() 這個方法返回是 double 類型,注意取值的范圍 0≤x<1( 能夠取到零值,注意除零異常 ),如果想獲取整數(shù)類型的隨機(jī)數(shù),不要將 x 放大 10 的若干倍然后取整,直接使用 Random 對象的 nextInt 或者 nextLong 方法。

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

  說明: 如果想獲取更加精確的納秒級時間值,用 System.nanoTime()。在 JDK8 中,針對統(tǒng)計(jì)時間等場景,推薦使用 Instant 類。
  • 1

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

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

8、【推薦】 對于“明確停止使用的代碼和配置”,如方法、變量、類、配置文件、動態(tài)配置屬性等要堅(jiān)決從程序中清理出去,避免造成過多垃圾。

異常處理

1、【強(qiáng)制】 不要捕獲 Java 類庫中定義的繼承自 RuntimeException 的運(yùn)行時異常類。

如:IndexOutOfBoundsException / NullPointerException,這類異常由程序員預(yù)檢查來規(guī)避,保證程序健壯性。  正例: if(obj != null) {...}  反例: try { obj.method() } catch(NullPointerException e){...}
  • 1
  • 2
  • 3
  • 4
  • 5

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

3、【強(qiáng)制】 對大段代碼進(jìn)行 try-catch,這是不負(fù)責(zé)任的表現(xiàn)。 catch 時請分清穩(wěn)定代碼和非穩(wěn)定代碼,穩(wěn)定代碼指的是無論如何不會出錯的代碼。對于非穩(wěn)定代碼的 catch 盡可能進(jìn)行區(qū)分異常類型,再做對應(yīng)的異常處理。

4、【強(qiáng)制】 捕獲異常是為了處理它,不要捕獲了卻什么都不處理而拋棄之,如果不想處理它,請將該異常拋給它的調(diào)用者。最外層的業(yè)務(wù)使用者,必須處理異常,將其轉(zhuǎn)化為用戶可以理解的內(nèi)容。

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

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

  說明: 如果 JDK7,可以使用 try-with-resources 方式。
  • 1

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

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

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

9、【推薦】 方法的返回值可以為 null,不強(qiáng)制返回空集合,或者空對象等,必須添加注釋充分說明什么情況下會返回 null 值。調(diào)用方需要進(jìn)行 null 判斷防止 NPE 問題。

  說明: 本規(guī)約明確防止 NPE 是調(diào)用者的責(zé)任。即使被調(diào)用方法返回空集合或者空對象,對調(diào)用者來說,也并非高枕無憂,必須考慮到遠(yuǎn)程調(diào)用失敗,運(yùn)行時異常等場景返回 null 的情況。
  • 1

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

  1) 返回類型為包裝數(shù)據(jù)類型,有可能是 null,返回 int 值時注意判空。  反例: public int f(){ return Integer 對象}; 如果為 null,自動解箱拋 NPE?! ?span>2) 數(shù)據(jù)庫的查詢結(jié)果可能為 null?! ?span>3) 集合里的元素即使 isNotEmpty,取出的數(shù)據(jù)元素也可能為 null?! ?span>4) 遠(yuǎn)程調(diào)用返回對象,一律要求進(jìn)行 NPE 判斷?! ?span>5) 對于 Session 中獲取的數(shù)據(jù),建議 NPE 檢查,避免空指針?! ?span>6) 級聯(lián)調(diào)用 obj.getA().getB().getC(); 一連串調(diào)用,易產(chǎn)生 NPE。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

11、【推薦】 在代碼中使用“拋異?!边€是“返回錯誤碼”,對于公司外的 http/api 開放接口必須使用“錯誤碼”; 而應(yīng)用內(nèi)部推薦異常拋出; 跨應(yīng)用間 RPC 調(diào)用優(yōu)先考慮使用 Result 方式,封裝 isSuccess、 “錯誤碼”、 “錯誤簡短信息”。

  說明: 關(guān)于 RPC 方法返回方式使用 Result 方式的理由:    1) 使用拋異常返回方式,調(diào)用方如果沒有捕獲到就會產(chǎn)生運(yùn)行時錯誤?!   ?span>2) 如果不加棧信息,只是 new 自定義異常,加入自己的理解的 error message,對于調(diào)用端解決問題的幫助不會太多。如果加了棧信息,在頻繁調(diào)用出錯的情況下,數(shù)據(jù)序列化和傳輸?shù)男阅軗p耗也是問題。
  • 1
  • 2
  • 3
  • 4
  • 5

12、【推薦】 定義時區(qū)分 unchecked / checked 異常,避免直接使用 RuntimeException 拋出,更不允許拋出 Exception 或者 Throwable,應(yīng)使用有業(yè)務(wù)含義的自定義異常。推薦業(yè)界已定義過的自定義異常,如: DAOException / ServiceException 等。

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

  說明: 隨意復(fù)制和粘貼代碼,必然會導(dǎo)致代碼的重復(fù),在以后需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是共用模塊。  正例: 一個類中有多個 public 方法,都需要進(jìn)行數(shù)行相同的參數(shù)校驗(yàn)操作,這個時候請抽取:  private boolean checkParam(DTO dto){...}
  • 1
  • 2
  • 3
  • 4
  • 5

建表規(guī)約

1、【強(qiáng)制】 表達(dá)是與否概念的字段,必須使用 is_xxx 的方式命名,數(shù)據(jù)類型是 unsigned tinyint( 1 表示是, 0 表示否 ),此規(guī)則同樣適用于 odps 建表。

  說明:任何字段如果為非負(fù)數(shù),必須是 unsigned。
  • 1

2、【強(qiáng)制】 表名、字段名必須使用小寫字母或數(shù)字; 禁止出現(xiàn)數(shù)字開頭,禁止兩個下劃線中間只出現(xiàn)數(shù)字。數(shù)據(jù)庫字段名的修改代價很大,因?yàn)闊o法進(jìn)行預(yù)發(fā)布,所以字段名稱需要慎重考慮。

  正例:getter_admin, task_config, level3_name  反例:GetterAdmin, taskConfig, level_3_name
  • 1
  • 2
  • 3

3、【強(qiáng)制】 表名不使用復(fù)數(shù)名詞。

  說明: 表名應(yīng)該僅僅表示表里面的實(shí)體內(nèi)容,不應(yīng)該表示實(shí)體數(shù)量,對應(yīng)于 DO 類名也是單數(shù)形式,符合表達(dá)習(xí)慣。
  • 1

4、【強(qiáng)制】 禁用保留字,如 desc、 range、 match、 delayed 等, 請參考 MySQL 官方保留字。

5、【強(qiáng)制】 唯一索引名為 uk_字段名; 普通索引名則為 idx_字段名。

  說明: uk_ 即 unique key; idx_ 即 index 的簡稱。
  • 1

6、【強(qiáng)制】 小數(shù)類型為 decimal,禁止使用 float 和 double。

  說明: floatdouble 在存儲的時候,存在精度損失的問題,很可能在值的比較時,得到不正確的結(jié)果。如果存儲的數(shù)據(jù)范圍超過 decimal 的范圍,建議將數(shù)據(jù)拆成整數(shù)和小數(shù)分開存儲。
  • 1

7、【強(qiáng)制】 如果存儲的字符串長度幾乎相等,使用 char 定長字符串類型。

8、【強(qiáng)制】 varchar 是可變長字符串,不預(yù)先分配存儲空間,長度不要超過 5000,如果存儲長度大于此值,定義字段類型為 text,獨(dú)立出來一張表,用主鍵來對應(yīng),避免影響其它字段索引效率。

9、【強(qiáng)制】 表必備三字段: id, gmt_create, gmt_modified。

  說明: 其中 id 必為主鍵,類型為 unsigned bigint、單表時自增、步長為 1。 gmt_create,gmt_modified 的類型均為 date_time 類型。
  • 1

10、【推薦】 表的命名最好是加上“業(yè)務(wù)名稱_表的作用”。

  正例: tiger_task / tiger_reader / mpp_config
  • 1

11、【推薦】 庫名與應(yīng)用名稱盡量一致。

12、【推薦】 如果修改字段含義或?qū)ψ侄伪硎镜臓顟B(tài)追加時,需要及時更新字段注釋。

13、【推薦】 字段允許適當(dāng)冗余,以提高性能,但是必須考慮數(shù)據(jù)同步的情況。冗余字段應(yīng)遵循:

  1) 不是頻繁修改的字段。  2) 不是 varchar 超長字段,更不能是 text 字段。  正例: 商品類目名稱使用頻率高, 字段長度短,名稱基本一成不變, 可在相關(guān)聯(lián)的表中冗余存儲類目名稱,避免關(guān)聯(lián)查詢。
  • 1
  • 2
  • 3
  • 4
  • 5

14、【推薦】 單表行數(shù)超過 500 萬行或者單表容量超過 2GB,才推薦進(jìn)行分庫分表。

  說明: 如果預(yù)計(jì)三年后的數(shù)據(jù)量根本達(dá)不到這個級別,請不要在創(chuàng)建表時就分庫分表。
  • 1

15、【參考】 合適的字符存儲長度,不但節(jié)約數(shù)據(jù)庫表空間、節(jié)約索引存儲,更重要的是提升檢索速度。

  正例: 人的年齡用 unsigned tinyint( 表示范圍 0-255,人的壽命不會超過 255 歲); 海龜就必須是 smallint,但如果是太陽的年齡,就必須是 int; 如果是所有恒星的年齡都加起來,那么就必須使用 bigint。
  • 1

索引規(guī)約

1、【強(qiáng)制】 業(yè)務(wù)上具有唯一特性的字段,即使是組合字段,也必須建成唯一索引。

  說明: 不要以為唯一索引影響了 insert 速度,這個速度損耗可以忽略,但提高查找速度是明顯的; 另外,即使在應(yīng)用層做了非常完善的校驗(yàn)和控制,只要沒有唯一索引,根據(jù)墨菲定律,必然有臟數(shù)據(jù)產(chǎn)生。
  • 1

2、【強(qiáng)制】 超過三個表禁止 join。需要 join 的字段,數(shù)據(jù)類型保持絕對一致; 多表關(guān)聯(lián)查詢時,保證被關(guān)聯(lián)的字段需要有索引。

  說明:即使雙表 join 也要注意表索引、 SQL 性能。
  • 1

3、【強(qiáng)制】 在 varchar 字段上建立索引時,必須指定索引長度,沒必要對全字段建立索引,根據(jù)實(shí)際文本區(qū)分度決定索引長度。

  說明:索引的長度與區(qū)分度是一對矛盾體,一般對字符串類型數(shù)據(jù),長度為 20 的索引,區(qū)分度會高達(dá) 90%以上,可以使用 count(distinct left(列名, 索引長度))/count(*)的區(qū)分度來確定。
  • 1

4、【強(qiáng)制】 頁面搜索嚴(yán)禁左模糊或者全模糊,如果需要請走搜索引擎來解決。

  說明:索引文件具有 B-Tree 的最左前綴匹配特性,如果左邊的值未確定,那么無法使用此索引。
  • 1

5、【 推薦】 如果有 order by 的場景,請注意利用索引的有序性。 order by 最后的字段是組合索引的一部分,并且放在索引組合順序的最后,避免出現(xiàn) file_sort 的情況,影響查詢性能。

  正例:where a=? and b=? order by c; 索引:a_b_c  反例:索引中有范圍查找,那么索引有序性無法利用,如:WHERE a>10 ORDER BY b; 索引a_b 無法排序。
  • 1
  • 2
  • 3

6、【推薦】 利用覆蓋索引來進(jìn)行查詢操作,來避免回表操作。

  說明:如果一本書需要知道第 11 章是什么標(biāo)題,會翻開第 11 章對應(yīng)的那一頁嗎?目錄瀏覽一下就好,這個目錄就是起到覆蓋索引的作用?! ≌?能夠建立索引的種類:主鍵索引、唯一索引、普通索引,而覆蓋索引是一種查詢的一種效果,用 explain 的結(jié)果, extra 列會出現(xiàn): using index。
  • 1
  • 2
  • 3

7、【推薦】 利用延遲關(guān)聯(lián)或者子查詢優(yōu)化超多分頁場景。

  說明:MySQL 并不是跳過 offset 行,而是取 offset N 行,然后返回放棄前 offset 行,返回N 行,那當(dāng) offset 特別大的時候,效率就非常的低下,要么控制返回的總頁數(shù),要么對超過特定閾值的頁數(shù)進(jìn)行 SQL 改寫?! ≌合瓤焖俣ㄎ恍枰@取的 id 段,然后再關(guān)聯(lián):  SELECT a.* FROM 表 1 a, (select id from1 where 條件 LIMIT 100000,20 ) b where a.id=b.id
  • 1
  • 2
  • 3
  • 4
  • 5

8、【推薦】 SQL 性能優(yōu)化的目標(biāo):至少要達(dá)到 range 級別, 要求是 ref 級別, 如果可以是 consts最好。

  說明:  1) consts 單表中最多只有一個匹配行( 主鍵或者唯一索引) ,在優(yōu)化階段即可讀取到數(shù)據(jù)?! ?span>2) ref 指的是使用普通的索引( normal index) ?! ?span>3) range 對索引進(jìn)行范圍檢索?! 》蠢?explain 表的結(jié)果, type=index,索引物理文件全掃描,速度非常慢,這個 index 級別比較 range 還低,與全表掃描是小巫見大巫。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

9、【推薦】 建組合索引的時候,區(qū)分度最高的在最左邊。

  正例: 如果 where a=? and b=? , a 列的幾乎接近于唯一值,那么只需要單建 idx_a 索引即可?! ≌f明: 存在非等號和等號混合判斷條件時,在建索引時,請把等號條件的列前置。如: where a>?and b=? 那么即使 a 的區(qū)分度更高,也必須把 b 放在索引的最前列。
  • 1
  • 2
  • 3

10、【參考】 創(chuàng)建索引時避免有如下極端誤解:

  1) 誤認(rèn)為一個查詢就需要建一個索引。  2) 誤認(rèn)為索引會消耗空間、嚴(yán)重拖慢更新和新增速度?! ?) 誤認(rèn)為唯一索引一律需要在應(yīng)用層通過“先查后插”方式解決
  • 1
  • 2
  • 3
  • 4
  • 5

結(jié)構(gòu)化查詢語言規(guī)約

1、【強(qiáng)制】不要使用 count(列名)或 count(常量)來替代 count(), count()就是 SQL92 定義的標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語法,跟數(shù)據(jù)庫無關(guān),跟 NULL 和非 NULL 無關(guān)。

  說明: count(*)會統(tǒng)計(jì)值為 NULL 的行,而 count(列名)不會統(tǒng)計(jì)此列為 NULL 值的行。
  • 1

2、【強(qiáng)制】 count(distinct col) 計(jì)算該列除 NULL 之外的不重復(fù)數(shù)量。注意 count(distinctcol1, col2) 如果其中一列全為 NULL,那么即使另一列有不同的值,也返回為 0。

3、【強(qiáng)制】當(dāng)某一列的值全是 NULL 時, count(col)的返回結(jié)果為 0,但 sum(col)的返回結(jié)果為NULL,因此使用 sum()時需注意 NPE 問題。

  正例: 可以使用如下方式來避免 sum 的 NPE 問題: SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;
  • 1

4、【強(qiáng)制】使用 ISNULL()來判斷是否為 NULL 值。注意: NULL 與任何值的直接比較都為 NULL。

  說明:  1NULL<>NULL 的返回結(jié)果是 NULL, 而不是 false?! ?span>2) NULL=NULL 的返回結(jié)果是 NULL, 而不是 true?! ?span>3) NULL<>1 的返回結(jié)果是 NULL,而不是 true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

5、【強(qiáng)制】 在代碼中寫分頁查詢邏輯時,若 count 為 0 應(yīng)直接返回,避免執(zhí)行后面的分頁語句。

6、【強(qiáng)制】 不得使用外鍵與級聯(lián),一切外鍵概念必須在應(yīng)用層解決。

  說明: ( 概念解釋 ) 學(xué)生表中的 student_id 是主鍵,那么成績表中的 student_id 則為外鍵。如果更新學(xué)生表中的 student_id,同時觸發(fā)成績表中的 student_id 更新,則為級聯(lián)更新。外鍵與級聯(lián)更新適用于單機(jī)低并發(fā),不適合分布式、高并發(fā)集群; 級聯(lián)更新是強(qiáng)阻塞,存在數(shù)據(jù)庫更新風(fēng)暴的風(fēng)險; 外鍵影響數(shù)據(jù)庫的插入速度。
  • 1

7、【強(qiáng)制】 禁止使用存儲過程,存儲過程難以調(diào)試和擴(kuò)展,更沒有移植性。

8、【強(qiáng)制】 數(shù)據(jù)訂正時,刪除和修改記錄時,要先 select,避免出現(xiàn)誤刪除,確認(rèn)無誤才能執(zhí)行更新語句。

9、【推薦】 in 操作能避免則避免,若實(shí)在避免不了,需要仔細(xì)評估 in 后邊的集合元素數(shù)量,控制在 1000 個之內(nèi)。

10、【參考】 如果有全球化需要,所有的字符存儲與表示,均以 utf-8 編碼,那么字符計(jì)數(shù)方法。

  說明:  SELECT LENGTH('輕松工作'); 返回為 12  SELECT CHARACTER_LENGTH('輕松工作'); 返回為 4  如果要使用表情,那么使用 utfmb4 來進(jìn)行存儲,注意它與 utf-8 編碼的區(qū)別。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

11、【參考】 TRUNCATE TABLE 比 DELETE 速度快,且使用的系統(tǒng)和事務(wù)日志資源少,但 TRUNCATE無事務(wù)且不觸發(fā) trigger,有可能造成事故,故不建議在開發(fā)代碼中使用此語句。

  說明: TRUNCATE TABLE 在功能上與不帶 WHERE 子句的 DELETE 語句相同。
  • 1

對象關(guān)系映射規(guī)約

1、【強(qiáng)制】 在表查詢中,一律不要使用 * 作為查詢的字段列表,需要哪些字段必須明確寫明。

  說明:  1) 增加查詢分析器解析成本。  2) 增減字段容易與 resultMap 配置不一致。
  • 1
  • 2
  • 3
  • 4
  • 5

2、【強(qiáng)制】 POJO 類的 boolean 屬性不能加 is,而數(shù)據(jù)庫字段必須加 is_,要求在 resultMap 中進(jìn)行字段與屬性之間的映射。

  說明: 參見定義 POJO 類以及數(shù)據(jù)庫字段定義規(guī)定,在 sql.xml 增加映射,是必須的。
  • 1

3、【強(qiáng)制】不要用 resultClass 當(dāng)返回參數(shù),即使所有類屬性名與數(shù)據(jù)庫字段一一對應(yīng),也需要定義; 反過來,每一個表也必然有一個與之對應(yīng)。

  說明: 配置映射關(guān)系,使字段與 DO 類解耦,方便維護(hù)。
  • 1

4、【強(qiáng)制】 xml 配置中參數(shù)注意使用: #{}, #param# 不要使用${} 此種方式容易出現(xiàn) SQL 注入。

5、【強(qiáng)制】 iBATIS 自帶的 queryForList(String statementName,int start,int size)不推薦使用。

  說明:其實(shí)現(xiàn)方式是在數(shù)據(jù)庫取到 statementName對應(yīng)的SQL語句的所有記錄,再通過 subList取 start,size 的子集合,線上因?yàn)檫@個原因曾經(jīng)出現(xiàn)過 OOM。  正例: 在 sqlmap.xml 中引入 #start#, #size#  Map<String, Object> map = new HashMap<String, Object>();  map.put('start', start);  map.put('size', size);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6、【強(qiáng)制】不允許直接拿 HashMap 與 Hashtable 作為查詢結(jié)果集的輸出。

7、【強(qiáng)制】更新數(shù)據(jù)表記錄時,必須同時更新記錄對應(yīng)的 gmt_modified 字段值為當(dāng)前時間。

8、【推薦】不要寫一個大而全的數(shù)據(jù)更新接口,傳入為 POJO 類,不管是不是自己的目標(biāo)更新字段,都進(jìn)行 update table set c1=value1,c2=value2,c3=value3; 這是不對的。執(zhí)行 SQL時,盡量不要更新無改動的字段,一是易出錯; 二是效率低; 三是 binlog 增加存儲。

9、【參考】 @Transactional 事務(wù)不要濫用。事務(wù)會影響數(shù)據(jù)庫的 QPS,另外使用事務(wù)的地方需要考慮各方面的回滾方案,包括緩存回滾、搜索引擎回滾、消息補(bǔ)償、統(tǒng)計(jì)修正等。

10、【參考】 中的 compareValue 是與屬性值對比的常量,一般是數(shù)字,表示相等時帶上此條件; 表示不為空且不為 null 時執(zhí)行; 表示不為 null 值時執(zhí)行。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服