這一秒不放棄,下一秒有奇跡
代碼規(guī)范整理
命名風格
- 代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束。
- 使用英文命名搜囱。
- 采用駝峰命名法。DO / BO / DTO / VO / AO / PO / UID 等例外柑土。
- 方法名蜀肘、參數名、成員變量稽屏、局部變量必須存儲駝峰形式扮宠。
- 常量全部大寫英文,單詞見用下劃線隔開诫欠,不要嫌長涵卵。
- 抽象類命名使用 Abstract 或 Base 開頭浴栽; 異常類命名使用 Exception 結尾荒叼; 測試類命名以它要測試的類的名稱開始,以 Test 結尾典鸡。
- 類型與中括號緊挨相連來表示數組被廓。 int[] arrayDemo
- POJO 類中布爾類型的變量,都不要加 is 前綴萝玷,否則部分框架解析會引起序列化錯誤嫁乘。
- 包名統(tǒng)一使用小寫,點分隔符之間有且僅有一個自然語義的英語單詞球碉。包名統(tǒng)一使用單數形式蜓斧,但是類名如果有復數含義,類名可以使用復數形式睁冬。
- 杜絕完全不規(guī)范的縮寫挎春, 避免望文不知義。
- 如果模塊豆拨、 接口直奋、類、方法使用了設計模式施禾,在命名時需體現出具體模式脚线。
- 接口類中的方法和屬性不要加任何修飾符號(public 也不要加) ,保持代碼的簡潔
性弥搞,并加上有效的 Javadoc 注釋邮绿。 - 對于 Service 和 DAO 類渠旁,基于 SOA 的理念,暴露出來的服務一定是接口船逮,內部的實現類用 Impl 的后綴與接口區(qū)別一死。
- 如果是形容能力的接口名稱,取對應的形容詞為接口名(通常是–able 的形式) 傻唾。AbstractTranslator 實現 Translatable 接口投慈。
- 枚舉類名建議帶上 Enum 后綴,枚舉成員名稱需要全大寫冠骄,單詞間用下劃線隔開伪煤。
- 各層命名規(guī)約:
A) Service/DAO 層方法命名規(guī)約
1) 獲取單個對象的方法用 get 做前綴。
2) 獲取多個對象的方法用 list 做前綴凛辣,復數形式結尾如: listObjects抱既。
3) 獲取統(tǒng)計值的方法用 count 做前綴。
4) 插入的方法用 save/insert 做前綴扁誓。
5) 刪除的方法用 remove/delete 做前綴防泵。
6) 修改的方法用 update 做前綴。
B) 領域模型命名規(guī)約
1) 數據對象: xxxDO蝗敢, xxx 即為數據表名捷泞。
2) 數據傳輸對象: xxxDTO, xxx 為業(yè)務領域相關的名稱寿谴。
3) 展示對象: xxxVO锁右, xxx 一般為網頁名稱。
4) POJO 是 DO/DTO/BO/VO 的統(tǒng)稱讶泰,禁止命名成 xxxPOJO咏瑟。
常量定義
- 不允許任何魔法值(即未經預先定義的常量) 直接出現在代碼中。
- 在 long 或者 Long 賦值時痪署, 數值后使用大寫的 L码泞,不能是小寫的 l,小寫容易跟數字 1 混淆狼犯,造成誤解余寥。
- 不要使用一個常量類維護所有常量, 要按常量功能進行歸類辜王,分開維護劈狐。
- 常量的復用層次有五層:跨應用共享常量、應用內共享常量呐馆、子工程內共享常量肥缔、包內共享常量、類內共享常量汹来。
1) 跨應用共享常量:放置在二方庫中续膳,通常是 client.jar 中的 constant 目錄下改艇。
2) 應用內共享常量:放置在一方庫中, 通常是子模塊中的 constant 目錄下坟岔。
反例: 易懂變量也要統(tǒng)一定義成應用內共享常量谒兄,兩位攻城師在兩個類中分別定義了表示“是”的變量:
類 A 中: public static final String YES = "yes";
類 B 中: public static final String YES = "y";
A.YES.equals(B.YES),預期是 true社付,但實際返回為 false承疲,導致線上問題。
3) 子工程內部共享常量:即在當前子工程的 constant 目錄下鸥咖。
4) 包內共享常量:即在當前包下單獨的 constant 目錄下燕鸽。
5) 類內共享常量:直接在類內部 private static final 定義。 - 如果變量值僅在一個固定范圍內變化用 enum 類型來定義啼辣。
代碼格式
- 大括號的使用約定啊研。如果是大括號內為空,則簡潔地寫成{}即可鸥拧,不需要換行党远;如果
是非空代碼塊則:
1) 左大括號前不換行。
2) 左大括號后換行富弦。
3) 右大括號前換行沟娱。
4) 右大括號后還有 else 等代碼則不換行; 表示終止的右大括號后必須換行舆声。 - 左小括號和字符之間不出現空格花沉; 同樣柳爽,右小括號和字符之間也不出現空格媳握;而左大括號前需要空格。
- if/for/while/switch/do 等保留字與括號之間都必須加空格磷脯。
- 任何二目蛾找、 三目運算符的左右兩邊都需要加一個空格。
- 采用 4 個空格縮進赵誓,禁止使用 tab 字符打毛。可配置
- 注釋的雙斜線與注釋內容之間有且僅有一個空格俩功。
- 單行字符數限制不超過 120 個幻枉,超出需要換行,換行時遵循如下原則:
1) 第二行相對第一行縮進 4 個空格诡蜓,從第三行開始熬甫,不再繼續(xù)縮進,參考示例蔓罚。
2) 運算符與下文一起換行椿肩。
3) 方法調用的點符號與下文一起換行瞻颂。
4) 方法調用中的多個參數需要換行時, 在逗號后進行郑象。
5) 在括號前不要換行贡这,見反例。 - 方法參數在定義和傳入時厂榛,多個參數逗號后邊必須加空格盖矫。
- 單個方法的總行數不超過 80 行。包括方法簽名击奶、結束右大括號炼彪、方法內代碼、注釋正歼、空行辐马、回車及任何不可見字符的總行數不超過 80 行。
- 有必要增加若干空格來使某一行的字符與上一行對應位置的字符對齊局义。
- 不同邏輯喜爷、不同語義、不同業(yè)務的代碼之間插入一個空行分隔開來以提升可讀性萄唇。任何情形檩帐, 沒有必要插入多個空行進行隔開。
OOP 規(guī)約
- 避免通過一個類的對象引用訪問此類的靜態(tài)變量或靜態(tài)方法另萤,無謂增加編譯器解析成
本湃密,直接用類名來訪問即可。 - 所有的覆寫方法四敞,必須加@Override 注解泛源。
- 相同參數類型,相同業(yè)務含義忿危,才可以使用 Java 的可變參數达箍,避免使用 Object。
- 外部正在調用或者二方庫依賴的接口铺厨,不允許修改方法簽名缎玫,避免對接口調用方產生影響。接口過時必須加@Deprecated 注解解滓,并清晰地說明采用的新接口或者新服務是什么赃磨。
- 不能使用過時的類或方法。
- Object 的 equals 方法容易拋空指針異常洼裤,應使用常量或確定有值的對象來調用equals邻辉。推薦使用 java.util.Objects#equals(JDK7 引入的工具類)
- 所有的相同類型的包裝類對象之間值的比較,全部使用 equals 方法比較。對于 Integer var = ? 在-128 至 127 范圍內的賦值恩沛, Integer 對象是在IntegerCache.cache 產生在扰,會復用已有對象,這個區(qū)間內的 Integer 值可以直接使用==進行判斷雷客,但是這個區(qū)間之外的所有數據芒珠,都會在堆上產生,并不會復用已有對象搅裙,這是一個大坑皱卓,推薦使用 equals 方法進行判斷。
- 關于基本數據類型與包裝數據類型的使用標準如下:
1)所有的 POJO 類屬性必須使用包裝數據類型部逮。
2)RPC 方法的返回值和參數必須使用包裝數據類型娜汁。
3)所有的局部變量使用基本數據類型。
POJO 類屬性沒有初值是提醒使用者在需要使用時兄朋,必須自己顯式地進行賦值掐禁,任何NPE 問題,或者入庫檢查颅和,都由使用者來保證 - 定義 DO/DTO/VO 等 POJO 類時傅事,不要設定任何屬性默認值。
- 序列化類新增屬性時峡扩,請不要修改 serialVersionUID 字段蹭越,避免反序列失敗教届; 如果完全不兼容升級响鹃,避免反序列化混亂,那么請修改 serialVersionUID 值案训。
- 構造方法里面禁止加入任何業(yè)務邏輯买置,如果有初始化邏輯,請放在 init 方法中萤衰。
- POJO 類必須寫 toString 方法堕义。使用 IDE 中的工具: source> generate toString時,如果繼承了另一個 POJO 類脆栋,注意在前面加一下 super.toString。
- 禁止在 POJO 類中洒擦,同時存在對應屬性 xxx 的 isXxx()和 getXxx()方法椿争。
- 使用索引訪問用 String 的 split 方法得到的數組時,需做最后一個分隔符后有無內容的檢查熟嫩,否則會有拋 IndexOutOfBoundsException 的風險秦踪。
- 當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序放置在一起椅邓。
- 類內方法定義的順序依次是:公有方法或保護方法 > 私有方法 > getter/setter
方法 - setter 方法中柠逞,參數名稱與類成員變量名稱一致, this.成員名 = 參數名景馁。在getter/setter 方法中板壮, 不要增加業(yè)務邏輯,增加排查問題的難度合住。
- 循環(huán)體內绰精,字符串的連接方式,使用 StringBuilder 的 append 方法進行擴展透葛。
- final 可以聲明類笨使、成員變量、方法僚害、以及本地變量硫椰,下列情況使用 final 關鍵字:
1) 不允許被繼承的類,如: String 類萨蚕。
2) 不允許修改引用的域對象最爬。
3) 不允許被重寫的方法,如: POJO 類的 setter 方法门岔。
4) 不允許運行過程中重新賦值的局部變量爱致。
5) 避免上下文重復使用一個變量,使用 final 描述可以強制重新定義一個變量寒随,方便更好地進行重構糠悯。 - 慎用 Object 的 clone 方法來拷貝對象。
- 類成員與方法訪問控制從嚴:
1) 如果不允許外部直接通過 new 來創(chuàng)建對象妻往,那么構造方法必須是 private互艾。
2) 工具類不允許有 public 或 default 構造方法。
3) 類非 static 成員變量并且與子類共享讯泣,必須是 protected纫普。
4) 類非 static 成員變量并且僅在本類使用,必須是 private好渠。
5) 類 static 成員變量如果僅在本類使用蹄殃,必須是 private。
6) 若是 static 成員變量殖演, 考慮是否為 final猾漫。
7) 類成員方法只供類內部調用,必須是 private霍掺。
8) 類成員方法只對繼承類公開匾荆,那么限制為 protected拌蜘。
集合處理
- 關于 hashCode 和 equals 的處理,遵循如下規(guī)則:
1) 只要重寫 equals牙丽,就必須重寫 hashCode简卧。
2) 因為 Set 存儲的是不重復的對象,依據 hashCode 和 equals 進行判斷烤芦,所以 Set 存儲的對象必須重寫這兩個方法举娩。
3) 如果自定義對象作為 Map 的鍵,那么必須重寫 hashCode 和 equals拍棕。 - ArrayList的subList結果不可強轉成ArrayList晓铆,否則會拋出 ClassCastException異常, 即 java.util.RandomAccessSubList cannot be cast to java.util.ArrayList绰播。
- 在 subList 場景中骄噪, 高度注意對原集合元素的增加或刪除, 均會導致子列表的遍歷蠢箩、增加链蕊、刪除產生 ConcurrentModificationException 異常
- 使用集合轉數組的方法,必須使用集合的 toArray(T[] array)谬泌,傳入的是類型完全一樣的數組滔韵,大小就是 list.size()。
- 使用工具類 Arrays.asList()把數組轉換成集合時掌实,不能使用其修改集合相關的方法陪蜻,它的 add/remove/clear 方法會拋出 UnsupportedOperationException 異常。
- 泛型通配符<? extends T>來接收返回的數據贱鼻,此寫法的泛型集合不能使用 add 方法宴卖, 而<? super T>不能使用 get 方法,作為接口調用賦值時易出錯邻悬。
- 不要在 foreach 循環(huán)里進行元素的 remove/add 操作症昏。 remove 元素請使用 Iterator方式,如果并發(fā)操作父丰,需要對 Iterator 對象加鎖肝谭。
- 在 JDK7 版本及以上, Comparator 實現類要滿足如下三個條件蛾扇,不然 Arrays.sort攘烛,Collections.sort 會報 IllegalArgumentException 異常。
說明: 三個條件如下
1) x屁桑, y 的比較結果和 y医寿, x 的比較結果相反。
2) x>y蘑斧, y>z, 則 x>z。
3) x=y竖瘾, 則 x沟突, z 比較結果和 y, z 比較結果相同捕传。 - 集合泛型定義時惠拭, 在 JDK7 及以上,使用 diamond 語法或全省略庸论。
- 集合初始化時职辅, 指定集合初始值大小。
- 使用 entrySet 遍歷 Map 類集合 KV聂示,而不是 keySet 方式進行遍歷域携。
- 高度注意 Map 類集合 K/V 能不能存儲 null 值的情況。
- 合理利用好集合的有序性(sort)和穩(wěn)定性(order)鱼喉,避免集合的無序性(unsort)和不穩(wěn)定性(unorder)帶來的負面影響秀鞭。
- 利用 Set 元素唯一的特性,可以快速對一個集合進行去重操作扛禽,避免使用 List 的contains 方法進行遍歷锋边、對比、 去重操作编曼。
控制語句
- 在一個 switch 塊內豆巨,每個 case 要么通過 break/return 等來終止,要么注釋說明程序將繼續(xù)執(zhí)行到哪一個 case 為止掐场; 在一個 switch 塊內往扔,都必須包含一個 default 語句并且放在最后,即使空代碼刻肄。
- 在 if/else/for/while/do 語句中必須使用大括號瓤球。 即使只有一行代碼,避免采用單行的編碼方式: if (condition) statements;
- 在高并發(fā)場景中敏弃,避免使用”等于”判斷作為中斷或退出的條件卦羡。如果并發(fā)控制沒有處理好,容易產生等值判斷被“擊穿”的情況麦到,使用大于或小于的區(qū)間判斷條件來代替绿饵。
- 表達異常的分支時, 少用 if-else 方式瓶颠,如果需要使用拟赊,絕對不要超過3層。
- 除常用方法(如 getXxx/isXxx)等外粹淋,不要在條件判斷中執(zhí)行其它復雜的語句吸祟,將復雜邏輯判斷的結果賦值給一個有意義的布爾變量名瑟慈,以提高可讀性。
- 循環(huán)體中的語句要考量性能屋匕,以下操作盡量移至循環(huán)體外處理葛碧,如定義對象、變量过吻、獲取數據庫連接进泼,進行不必要的 try-catch 操作(這個 try-catch 是否可以移至循環(huán)體外) 。
- 避免采用取反邏輯運算符纤虽。
- 下列情形乳绕,需要進行參數校驗:
1) 調用頻次低的方法。
2) 執(zhí)行時間開銷很大的方法逼纸。 此情形中洋措, 參數校驗時間幾乎可以忽略不計,但如果因為參數錯誤導致中間執(zhí)行回退樊展,或者錯誤呻纹,那得不償失。
3) 需要極高穩(wěn)定性和可用性的方法专缠。
4) 對外提供的開放接口雷酪,不管是 RPC/API/HTTP 接口。
5) 敏感權限入口涝婉。 - 下列情形哥力, 不需要進行參數校驗:
1) 極有可能被循環(huán)調用的方法。但在方法說明里必須注明外部參數檢查要求墩弯。
2) 底層調用頻度比較高的方法吩跋。畢竟是像純凈水過濾的最后一道,參數錯誤不太可能到底層才會暴露問題渔工。一般 DAO 層與 Service 層都在同一個應用中锌钮,部署在同一臺服務器中,所以 DAO 的參數校驗引矩,可以省略梁丘。
3) 被聲明成 private 只會被自己代碼所調用的方法,如果能夠確定調用方法的代碼傳入參數已經做過檢查或者肯定不會有問題旺韭,此時可以不校驗參數氛谜。
注釋規(guī)約
- 類、類屬性区端、類方法的注釋必須使用 Javadoc 規(guī)范值漫,使用/*內容/格式,不得使用 // xxx 方式织盼。
- 有的抽象方法(包括接口中的方法) 必須要用 Javadoc 注釋杨何、除了返回值酱塔、參數、異常說明外晚吞,還必須指出該方法做什么事情延旧,實現什么功能谋国。
- 所有的類都必須添加創(chuàng)建者和創(chuàng)建日期槽地。
- 方法內部單行注釋,在被注釋語句上方另起一行芦瘾,使用//注釋捌蚊。方法內部多行注釋使用/* */注釋,注意與代碼對齊近弟。
- 所有的枚舉類型字段必須要有注釋缅糟,說明每個數據項的用途。
- 與其“半吊子”英文來注釋祷愉,不如用中文注釋把問題說清楚窗宦。專有名詞與關鍵字保持英文原文即可。
- 代碼修改的同時二鳄,注釋也要進行相應的修改赴涵,尤其是參數、返回值订讼、異常髓窜、核心邏輯等的修改。
- 謹慎注釋掉代碼欺殿。 在上方詳細說明寄纵,而不是簡單地注釋掉。 如果無用脖苏,則刪除程拭。
- 對于注釋的要求:第一、能夠準確反應設計思想和代碼邏輯棍潘; 第二恃鞋、能夠描述業(yè)務含義,使別的程序員能夠迅速了解到代碼背后的信息蜒谤。完全沒有注釋的大段代碼對于閱讀者形同天書山宾,注釋是給自己看的,即使隔很長時間鳍徽,也能清晰理解當時的思路资锰; 注釋也是給繼任者看的,使其能夠快速接替自己的工作阶祭。
- 好的命名绷杜、代碼結構是自解釋的直秆,注釋力求精簡準確、表達到位鞭盟。避免出現注釋的一個極端:過多過濫的注釋圾结,代碼的邏輯一旦修改,修改注釋是相當大的負擔齿诉。
日復一日