1 方法行數不能超過50行,特殊情況除外;說明:如果行數過長不利于整個方法的閱讀了解。如果是筆記本建議控制在40以内。
2 方法參數不能多于7個,特殊情況除外;說明:參數過多不利于整個方法的閱讀了解。
3 變量名稱需有意義且符合駝峰式寫法,嚴禁出現a,b,c 等字元作為變量名稱。
4 嚴禁出現魔鬼數字(在代碼中沒有具體含義的數字、字元串)。
5 建立類名,方法名意義盡量切近目前功能子產品的功能,且符合駝峰式寫法。
6 If語句後必須寫花括号,嚴禁出現 if(true)後面直接寫代碼,需帶花括号{}。
7 條件判斷中必須有空格 如 if (1 == 2)。 等号兩邊需加空格。
8 嚴禁使用==判斷字元串值,需使用equals方法判斷。
9 與null對象進行判斷, 需寫成(null == xxx) 形式,null寫在前;說明:有時候如果将變量寫在前,恰好将==疏忽寫成= 就會造成 xxx = null,等于是給變量指派為null。
10 對目前對象進行null判斷,并且進行調用對象方法判斷時,形如if(null != xxx && xxx.size() > 0)需将null != xxx判斷寫在前,這樣如果為null,可以直接短路,防止空指針異常産生。
11 靜态常量名稱應大寫,多個單詞可用下劃線拼接,如 SELECT_NUMBER = 1。
12 方法注釋,若目前方法功能較為複雜,需以javadoc方式注釋進行說明,注釋需寫成形如
/**
*
* @author username
* @param oldStage
*/
13 無需再對boolean 值再進行判斷,直接使用即可,如 if (success) { TODO…}。
反例: if (success == true) { TODO…}
14 POJO 類中的任何布爾類型的變量,都不要加 is,否則部分架構解析會引起序列化錯誤。反例:定義為基本資料類型 boolean isSuccess;的屬性,它的方法也是 isSuccess(),RPC架構在反向解析的時候,“以為”對應的屬性名稱是 success,導緻屬性擷取不到,進而抛出異常。
15 if/for/while/switch/do 等保留字與左右括号之間都必須加空格。任何運算符左右必須加一個空格。說明:運算符包括指派運算符=、邏輯運算符&&、加減乘除符号、三目運作符等。
16 IDE 的 text file encoding 設定為 UTF-8。
17 Object的equals方法容易抛空指針異常,應使用常量或确定有值的對象來調用equals。
例如: "test".equals(object)
18 POJO 類必須寫 toString 方法。使用工具類 source> generate toString 時,如果繼
承了另一個 POJO 類,注意在前面加一下 super.toString。說明:在方法執行抛出異常時,可以直接調用 POJO 的 toString()方法列印其屬性值,便于排查問題。
19 使用索引通路用 String 的 split 方法得到的數組時,需做最後一個分隔符後有無内
容的檢查,否則會有抛 IndexOutOfBoundsException 的風險。說明:
String str = "a,b,c,,"; String[] ary = str.split(",");
//預期大于 3,結果是 3
System.out.println(ary.length);
20 【推薦】當一個類有多個構造方法,或者多個同名方法,這些方法應該按順序放置在一起,便于閱讀。
21 【推薦】 類内方法定義順序依次是:公有方法或保護方法 > 私有方法 > getter/setter
方法。
22 【推薦】setter 方法中,參數名稱與類成員變量名稱一緻,this.成員名=參數名。在
getter/setter 方法中,盡量不要增加業務邏輯,增加排查問題難度。
反例:
public Integer getData(){
if(true) {
return data + 100;
} else {
return data - 100;
}
23 【推薦】循環體内,字元串的聯接方式,使用 StringBuilder 的 append 方法進行擴充。
String str = "start";
for(int i=0; i<100; i++){
str = str + "hello";
說明:反編譯出的位元組碼檔案顯示每次循環都會 new 出一個 StringBuilder 對象,然後進行append 操作,最後通過 toString 方法傳回 String 對象,造成記憶體資源浪費。
24 【推薦】final 可提高程式響應效率,聲明成 final 的情況:
1) 不需要重新指派的變量,包括類屬性、局部變量。
2) 對象參數前加 final,表示不允許修改引用的指向。
3) 類方法确定不允許被重寫。
25 Map/Set 的 key 為自定義對象時,必須重寫 hashCode 和 equals。正例:String 重寫hashCode 和 equals 方法,是以我們可以非常愉快地使用 String 對象作為 key 來使用。
26 使用集合轉數組的方法,必須使用集合的 toArray(T[] array),傳入的是類型完全
一樣的數組,大小就是 list.size()。
反例:直接使用 toArray 無參方法存在問題,此方法傳回值隻能是 Object[]類,若強轉其它類型數組将出現 ClassCastException 錯誤。
正例:
List<String> list = new ArrayList<String>(2);
list.add("jun");
list.add("jiang");
String[] array = new String[list.size()];
array = list.toArray(array);
說明:使用 toArray 帶參方法,入參配置設定的數組空間不夠大時,toArray 方法内部将重新配置設定記憶體空間,并傳回新數組位址;如果數組元素大于實際所需,下标為[ list.size() ]的數組元素将被置為 null,其它數組元素保持原值,是以最好将方法入參數組大小定義與集合元素個數一緻
27 不要在 foreach 循環裡進行元素的 remove/add 操作。remove 元素請使用 Iterator
方式,如果并發操作,需要對 Iterator 對象加鎖。
List<String> a = new ArrayList<String>();
a.add("1");
a.add("2");
for (String temp : a) {
if("1".equals(temp)){
a.remove(temp);
說明:這個例子的執行結果會出乎大家的意料,那麼試一下把“1”換成“2”,會是同樣的結果嗎?
Iterator<String> it = a.iterator();
while(it.hasNext()){
String temp = it.next();
if(删除元素的條件){
it.remove();
28 【推薦】集合初始化時,盡量指定集合初始值大小。說明:ArrayList 盡量使用 ArrayList(int initialCapacity) 初始化。
29 【推薦】使用 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 值組合集合。
30 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 代替 Simpledateformatter,官方給出的解釋:simple beautiful strong
immutable thread-safe。
31 高并發時,同步調用應該去考量鎖的性能損耗。能用無鎖資料結構,就不要用鎖;能
鎖區塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。
32 多線程并行處理定時任務時,Timer 運作多個 TimeTask 時,隻要其中之一沒有捕獲
抛出的異常,其它任務便會自動終止運作,使用 ScheduledExecutorService 則沒有這個問題。
33 建立線程或線程池時請指定有意義的線程名稱,友善出錯時回溯。
34 在一個 switch 塊内,每個 case 要麼通過 break/return 來終止,要麼注釋說明程式
将繼續執行到哪一個 case 為止;在一個 switch 塊内,都必須包含一個 default 語句并且放在最後,即使它什麼代碼也沒有。
35 循環體中的語句要考量性能,以下操作盡量移至循環體外處理,如定義對象、變量、擷取資料庫連接配接,進行不必要的 try-catch 操作(這個 try-catch 是否可以移至循環體外)。
36 所有的抽象方法(包括接口中的方法)必須要用 javadoc 注釋、除了傳回值、參數、
異常說明外,還必須指出該方法做什麼事情,實作什麼功能。
說明:如有實作和調用注意事項,請一并說明。
37 所有的類都必須添加建立者資訊。
38 所有的枚舉類型字段必須要有注釋,說明每個資料項的用途。
39 代碼修改的同時,注釋也要進行相應的修改,尤其是參數、傳回值、異常、核心邏輯等的修改。
說明:代碼與注釋更新不同步,就像路網與導航軟體更新不同步一樣,如果導航軟體嚴重滞後,就失去了導航的意義。
40 【參考】注釋掉的代碼盡量要配合說明,而不是簡單的注釋掉。
說明:代碼被注釋掉有兩種可能性:1)後續會恢複此段代碼邏輯。2)永久不用。前者如果沒有備注資訊,難以知曉注釋動機。後者建議直接删掉(代碼倉庫儲存了曆史代碼)。
41 【參考】對于注釋的要求:第一、能夠準确反應設計思想和代碼邏輯;第二、能夠描述業務含義,使别的程式員能夠迅速了解到代碼背後的資訊。完全沒有注釋的大段代碼對于閱讀者形同天書,注釋是給自己看的,即使隔很長時間,也能清晰了解當時的思路;注釋也是給繼任者看的,使其能夠快速接替自己的工作。
42 錯誤,不能工作(FIXME):(标記人,标記時間,[預計處理時間])在注釋中用 FIXME 标記某代碼是錯誤的,而且不能工作,需要及時糾正的情況。
43 在使用正規表達式時,利用好其預編譯功能,可以有效加快正則比對速度。
說明:不要在方法體内定義:Pattern pattern = Pattern.compile(規則);
44 注意 Math.random() 這個方法傳回是 double 類型,注意取值範圍 0≤x<1(能夠取到零值,注意除零異常),如果想擷取整數類型的随機數,不要将 x 放大 10 的若幹倍然後取整,直接使用 Random 對象的 nextInt 或者 nextLong 方法。
45 擷取目前毫秒數:System.currentTimeMillis(); 而不是 new Date().getTime();
說明:如果想擷取更加精确的納秒級時間值,用 System.nanoTime。在 JDK8 中,針對統計時間等場景,推薦使用 Instant 類。
46 【推薦】任何資料結構的使用都應限制大小。說明:這點很難完全做到,但很多次的故障都是因為資料結構自增長,結果造成記憶體被吃光。
47 【推薦】對于“明确停止使用的代碼和配置”,如方法、變量、類、配置檔案、動态配置屬性等要堅決從程式中清理出去,避免造成過多垃圾。清理這類垃圾代碼是技術氣場,不要有這樣的觀念:“不做不錯,多做多錯”。
48 不要捕獲 Java 類庫中定義的繼承自 RuntimeException 的運作時異常類,如:
IndexOutOfBoundsException / NullPointerException,這類異常由程式員預檢查來規避,保證程式健壯性。
正例: if(obj != null) {...}
反例: try { obj.method() } catch(NullPointerException e){…}
49 異常不要用來做流程控制,條件控制,因為異常的處理效率比條件分支低。
50 finally 塊必須對資源對象、流對象進行關閉,有異常也要做 try-catch。
說明:如果 JDK7,可以使用 try-with-resources 方法。
51 不能在 finally 塊中使用 return,finally 塊中的 return 傳回後方法結束執行,不
會再執行 try 塊中的 return 語句。
52 避免出現重複的代碼(Don’t Repeat Yourself),即 DRY 原則。
說明:随意複制和粘貼代碼,必然會導緻代碼的重複,在以後需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是共用子產品。
正例:一個類中有多個 public 方法,都需要進行數行相同的參數校驗操作,這個時候請抽取:
private boolean checkParam(String str){...}
53 日志列印輸出的 POJO 類必須重寫 toString 方法,否則隻輸出此對象的 hashCode 值(位址值),沒啥參考意義。
54 大量地輸出無效日志,不利于系統性能提升,也不利于快速定位錯誤點。紀錄日志時請
思考:這些日志真的有人看嗎?看到這條日志你能做什麼?能不能給問題排查帶來好處?
55 中括号是數組類型的一部分,數組定義如下:String[] args;
反例:請勿使用 String args[]的方式來定義
56 抽象類命名使用 Abstract 或 Base 開頭;異常類命名使用 Exception 結尾;測試類命
名以它要測試的類的名稱開始,以 Test 結尾。
give me the ball!