天天看點

JAVA開發規範

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!