一、編程規範
(一)命名規範:(命名要望文知意,不要嫌長)
-
包名要統一小寫(xie)
-
類名、接口名遵從(cong) 駝峰式命名,DO / BO /DTO / VO / AO/PO例外
例子:MarcoPolo / UserDO / XmlService / TcpUdpDeal
-
方法名、參數名、成員變量、局部變量都統一使用 lowerCamelCase 風格
例子:localValue / getHttpMessage() / inputUserId
-
常量命名全部大寫(xie) ,單詞間下劃線隔開
例子:MAX_STOCK_COUNT
-
枚舉(ju) 類名要以Enum為(wei) 後綴,且枚舉(ju) 成員名稱要全大寫(xie) ,和常量命名一樣
例子:枚舉(ju) 類名 ProcessStatusEnum 枚舉(ju) 成員名稱 SUCCESS/UNKOWN_REASON
-
Service/DAO層方法命名:
-
獲取單個(ge) 對象的方法用get做前綴
-
獲取多個(ge) 對象的方法用list做前綴
-
獲取統計值的方法用count做前綴
-
插入的方法用save/insert做前綴
-
刪除的方法用remove/delete做前綴
-
修改的方法用update做前綴
-
領域模型命名
-
查詢數據庫對象:xxxPO
-
業(ye) 務邏輯層對象:xxxBO
-
接收客戶端參數的對像:xxxVO
-
層級之間的數據傳(chuan) 輸對象:xxxDTO
(二)常量定義
-
不允許任何魔法值(即未經定義(yi) 的常量)直接出現在代碼中。常量的複用層次有五層:跨應用共享常量、應用內(nei) 共享常量、子工程內(nei) 共享常量、包內(nei) 共享常量、類內(nei) 共享常量
-
跨應用共享常量:放置在二方庫中,通常是client.jar中的constant目錄下
-
應用內(nei) 共享常量:放置在一方庫中,通常是modules中的constant目錄下
-
子工程內(nei) 部共享常量:即在當前子工程的constant目錄下
-
包內(nei) 共享常量:即在當前包下單獨的constant目錄下
-
類內(nei) 共享常量:直接在類內(nei) 部private static final定義(yi)
-
如果變量值在一個(ge) 範圍內(nei) 變化,且帶有名稱之外的延展屬性,定義(yi) 為(wei) 枚舉(ju) 類
例子:數字就是延伸信息,標識星期幾
public Enum { MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6),SUNDAY(7);}
(三)代碼格式
-
方法體(ti) 內(nei) 的執行語句組、變量的定義(yi) 語句組、不同的業(ye) 務邏輯之間或者不同的語義(yi) 之間插入一個(ge) 空行。
-
單行字符數限製不超過 120 個(ge) ,超出需要換行,換行時遵循如下原則:
-
第二行相對第一行縮進 4 個(ge) 空格,從(cong) 第三行開始,不再繼續縮進,參考示例。
-
運算符與(yu) 下文一起換行。
-
方法調用的點符號與(yu) 下文一起換行。
-
4方法調用時,多個(ge) 參數,需要換行時,在逗號後進行。
-
在括號前不要換行
-
適當加空格進行格式整理(idea使用用快捷鍵ctrl+alt+L快速整理)
(四)OOP規範
-
所有覆寫(xie) 的方法,必須加@Override注解。可以準確判斷是否覆蓋成功。另外,如果在抽象中對方法簽名進行修改,其實現類會(hui) 馬上編譯報錯
-
外部正在調用或者二方庫依賴的接口,不允許修改方法簽名,避免對接口調用方產(chan) 生影響。接口過時必須加@Deprecated 注解,並清晰地說明采用的新接口或者新服務是什麽(me) 。
-
調用equals方法比較時,應使用常量或確定有值的對象來調用equals方法,並且包裝類對象之間的比較,全部使用 equals 方法比較
-
關(guan) 於(yu) 基本數據類型和包裝數據類型的使用標準:
-
所有的POJO類屬性必須使用包裝數據類型
-
RPC方法的返回值和參數必須使用包裝數據類型
-
所有的局部變量推薦使用基本數據類型
-
構造方法裏麵禁止加入任何業(ye) 務邏輯,如果有初始化邏輯,請放在 init 方法中
-
類內(nei) 方法定義(yi) 順序依次是:公有方法或保護方法 > 私有方法 > getter/setter方法。
說明:公有方法是類的調用者和維護者最關(guan) 心的方法,首屏展示最好;保護方法雖然隻是子類關(guan) 心,也可能是“模板設計模式”下的核心方法;而私有方法外部一般不需要特別關(guan) 心,是一個(ge) 黑盒實現;因為(wei) 承載的信息價(jia) 值較低,所有 Service 和 DAO 的 getter/setter 方法放在類體(ti)
-
循環體(ti) 內(nei) ,字符串的連接方式,使用 StringBuilder 的 append 方法進行擴展。
說明:反編譯出的字節碼文件顯示每次循環都會(hui) new 出一個(ge) StringBuilder 對象,然後進行append 操作,最後通過 toString 方法返回 String 對象,造成內(nei) 存資源浪費
-
類成員與(yu) 方法訪問控製從(cong) 嚴(yan) :
-
如果不允許外部直接通過 new 來創建對象,那麽(me) 構造方法必須是 private。
-
工具類不允許有 public 或 default 構造方法。
-
類非 static 成員變量並且與(yu) 子類共享,必須是 protected。
-
類非 static 成員變量並且僅(jin) 在本類使用,必須是 private。
-
類 static 成員變量如果僅(jin) 在本類使用,必須是 private。
-
若是 static 成員變量,必須考慮是否為(wei) final。
-
類成員方法隻供類內(nei) 部調用,必須是 private。
-
類成員方法隻對繼承類公開,那麽(me) 限製為(wei) protected。
說明:任何類、方法、參數、變量,嚴(yan) 控訪問範圍。過於(yu) 寬泛的訪問範圍,不利於(yu) 模塊解耦
(五)集合處理
-
在 subList 場景中,高度注意對原集合元素個(ge) 數的修改,會(hui) 導致子列表的遍曆、增加、刪除均會(hui) 產(chan) 生 ConcurrentModificationException 異常。並且不要在 foreach 循環裏進行元素的 remove/add 操作。remove 元素請使用 Iterator方式,如果並發操作,需要對 Iterator 對象加鎖。
//正例: Iterator iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (刪除元素的條件) { iterator.remove(); } } //反例: List list = new ArrayList(); list.add("1"); list.add("2"); for (String item : list) { if ("1".equals(item)) { list.remove(item); } }
-
使用集合轉數組的方法,必須使用集合的 toArray(T[] array),傳(chuan) 入的是類型完全一樣的數組,大小就是 list.size()。
說明:使用 toArray 帶參方法,入參分配的數組空間不夠大時,toArray 方法內(nei) 部將重新分配
內(nei) 存空間,並返回新數組地址;如果數組元素大於(yu) 實際所需,下標為(wei) [ list.size() ]的數組
元素將被置為(wei) null,其它數組元素保持原值,因此最好將方法入參數組大小定義(yi) 與(yu) 集合元素
個(ge) 數一致。
-
使用工具類 Arrays.asList()把數組轉換成集合時,不能使用其修改集合相關(guan) 的方法,它的 add/remove/clear 方法會(hui) 拋出 UnsupportedOperationException 異常。
說明:asList 的返回對象是一個(ge) Arrays 內(nei) 部類,並沒有實現集合的修改方法。Arrays.asList體(ti) 現的是適配器模式,隻是轉換接口,後台的數據仍是數組。
-
泛型通配符<? extends T>來接收返回的數據,此寫(xie) 法的泛型集合不能使用 add 方法,而<? super T>不能使用 get 方法,做為(wei) 接口調用賦值時易出錯。
說明:擴展說一下 PECS(Producer Extends Consumer Super)原則:第一、頻繁往外讀取內(nei) 容的,適合用<? extends T>。第二、經常往裏插入的,適合用<? super T>。
/** * ? extends T 表示T或T的子類 * ? super T 表示T或T的父類 * ? 表示可以是任意類型 **/ class Gent<T> { public void test(){ System.out.println("gent"); } } class SupC { public void test(){ System.out.println("supC"); } } class Bc extends SupC { //入參隻能是SupC或SupC的子類 public void testExtends(gent<? extends SupC> o){ System.out.println("Bc"); } //入參隻能是Bc或Bc的父類 public void testSuper(gent<? super Bc> o){ System.out.println("Bc"); } //入參可以是任意類型 public void testSuper(gent<?> o){ System.out.println("gent"); } }
-
合理利用好集合的有序性(sort)和穩定性(order),避免集合的無序性(unsort)和不穩定性(unorder)帶來的負麵影響。
說明:有序性是指遍曆的結果是按某種比較規則依次排列的。穩定性指集合每次遍曆的元素次序是一定的。如:ArrayList 是 order/unsort;HashMap 是 unorder/unsort;TreeSet 是order/sort。
-
利用 Set 元素唯一的特性,可以快速對一個(ge) 集合進行去重操作,避免使用 List 的contains 方法進行遍曆、對比、去重操作
//兩(liang) 個(ge) Set比較找出交集、差集、並集 public static void setCompare() { Set<Integer> result = new HashSet<Integer>(); Set<Integer> set1 = new HashSet<Integer>() {{ add(1); add(3); add(4); }}; System.out.println("set1 = " + set1.toString()); Set<Integer> set2 = new HashSet<Integer>() {{ add(1); add(2); add(3); }}; System.out.println("set2 = " + set2.toString()); //交集:set1和set2相同的元素 result.clear(); result.addAll(set1); result.retainAll(set2); System.out.println("交集:" + result); //result結果:[1, 3] //差集:元素存在set1,但不存在set2 result.clear(); result.addAll(set1); result.removeAll(set2); System.out.println("差集:" + result); //result結果:[4] //並集:set1的set2的元素之和 result.clear(); result.addAll(set1); result.addAll(set2); System.out.println("並集:" + result); //result結果:[1, 2, 3, 4] }
(六)並發處理
-
高並發時,同步調用應該去考量鎖的性能損耗。能用無鎖數據結構,就不要用鎖;能鎖區塊,就不要鎖整個(ge) 方法體(ti) ;能用對象鎖,就不要用類鎖。
說明:盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調用 RPC 方法。
-
並發修改同一記錄時,避免更新丟(diu) 失,需要加鎖。要麽(me) 在應用層加鎖,要麽(me) 在緩存加鎖,要麽(me) 在數據庫層使用樂(le) 觀鎖,使用 version 作為(wei) 更新依據。
說明:如果每次訪問衝(chong) 突概率小於(yu) 20%,推薦使用樂(le) 觀鎖,否則使用悲觀鎖。樂(le) 觀鎖的重試次數不得小於(yu) 3 次。
-
避免 Random 實例被多線程使用,雖然共享該實例是線程安全的,但會(hui) 因競爭(zheng) 同一seed 導致的性能下降。
說明:Random 實例包括 java.util.Random 的實例或者 Math.random()的方式。正例:在 JDK7 之後,可 以直接使用 API ThreadLocalRandom,而在 JDK7 之前,需要編碼保證每個(ge) 線程持有一個(ge) 實例。
-
HashMap 在容量不夠進行 resize 時由於(yu) 高並發可能出現死鏈,導致 CPU 飆升,在開發過程中可以使用其它數據結構或加鎖來規避此風險
(七)控製語句
-
在一個(ge) switch 塊內(nei) ,每個(ge) case 要麽(me) 通過 break/return 等來終止,要麽(me) 注釋說明程序將繼續執行到哪一個(ge) case 為(wei) 止;在一個(ge) switch 塊內(nei) ,都必須包含一個(ge) default 語句並且放在最後,即使它什麽(me) 代碼也沒有。
-
在 if/else/for/while/do 語句中必須使用大括號。即使隻有一行代碼,避免采用單行的編碼方式:if (condition) statements;
-
表達異常的分支時,少用 if-else 方式,這種方式可以改寫(xie) 成:if (condition) {...return obj;}// 接著寫(xie) else 的業(ye) 務邏輯代碼;
說明:如果非得使用 if()...else if()...else...方式表達邏輯,避免後續代碼維護困難,請勿超過 3 層。
正例:超過 3 層的 if-else 的邏輯判斷代碼可以使用衛語句、策略模式、狀態模式等來實現,
衛語句:
//改造前(看著亂(luan) ,不清楚每個(ge) 邏輯分支的具體(ti) 條件) //當 a等於(yu) 1 if (a == 1){ //當 b等於(yu) 2 if (b == 2){ ... } else { //當 b不等於(yu) 1 //c等於(yu) 3 if (c == 3){ ... } } }else{ //當 a不等於(yu) 1 //當 d等於(yu) 4 if(d == 4){ ... } } //改造後(從(cong) 上到下,看著清晰明了,並清楚每個(ge) 邏輯分支對應的條件) //情況一:當 a等於(yu) 1 並 b等於(yu) 2 if(a == 1&&b == 2){ ... } //情況二:當 a等於(yu) 1 並 b不等於(yu) 2 並 c等於(yu) 3 if(a == 1&&b != 2&&c == 3){ ... } //情況三:當 a不等於(yu) 1 並 d等於(yu) 4 if(a != 1&&d == 4){ ... }
策略模式:
/** * 實現不同動物發出不同聲音 * 如:狗--汪汪 貓--喵喵 牛--哞哞 羊--咩咩 * @author gz * */ //改造前 (後期加多種動物類型,每次都需要修改共用的邏輯,易出錯,且不易維護) public class AnimalCryTest { private static final String DOG = "狗"; private static final String CAR = "貓"; private static final String CATTLE = "牛"; private static final String SHEEP = "羊"; /** * 動物的叫聲 * @param animalName 動物名稱 */ public static void animalCry(String animalName){ if (DOG.equals(animalName)){ System.out.println(animalName+"----汪汪"); }else if (CAR.equals(animalName)){ System.out.println(animalName+"----喵喵"); }else if (CATTLE.equals(animalName)){ System.out.println(animalName+"----哞哞"); }else { System.out.println(animalName+"----咩咩"); } } public static void main(String[] args) { // 狗--汪汪 animalCry(DOG); // 貓--喵喵 animalCry(CAR); // 牛--哞哞 animalCry(CATTLE); // 羊--咩咩 animalCry(SHEEP); } } //改造後(後期加多種動物類型,隻需要實現對應功能的接口,各個(ge) 邏輯是相互獨立的,不易出錯,易維護) /** * 1、定義(yi) 一個(ge) 接口 **/ interface Animal { /** * 動物叫聲 */ void animalCry(); } /** * 2、創建實現該接口的實現類 **/ class Dog implements Animal { @Override public void animalCry() { System.out.println("狗----汪汪"); } } class Car implements Animal { @Override public void animalCry() { System.out.println("貓----喵喵"); } } class Cattle implements Animal { @Override public void animalCry() { System.out.println("牛----哞哞"); } } class Sheep implements Animal { @Override public void animalCry() { System.out.println("羊----咩咩"); } } /** * 3、多態性質,根據實例化對象的不同,調用實例化對象對應的具體(ti) 方法 **/ public class AnimalCryTest { public static void main(String[] args) { // 創建狗的實例對象,並調用其對應的animalCry方法 狗--汪汪 Animal dog = new Dog(); dog.animalCry(); // 創建貓的實例對象,並調用其對應的animalCry方法 貓--喵喵 Animal car = new Car(); car.animalCry(); // 創建牛的實例對象,並調用其對應的animalCry方法 牛--哞哞 Animal cattle = new Cattle(); cattle.animalCry(); // 創建羊的實例對象,並調用其對應的animalCry方法 羊--咩咩 Animal sheep = new Sheep(); sheep.animalCry(); } }
狀態模式:
/** * 在"投了25分錢"的狀態下"轉動曲柄",會(hui) 售出糖果;而在"沒有25分錢"的狀態下"轉動曲柄"會(hui) 提示請先投幣。 * 四個(ge) 狀態: * 1、沒有硬幣狀態 * 2、投幣狀態 * 3、出售糖果狀態 * 4、糖果售盡狀態 * 四個(ge) 動作: * 1、投幣 * 2、退幣 * 3、轉動出糖曲軸 * 4、發糖 * @author gz */ //改造前 public class NoPatternGumballMachine{ /* * 四個(ge) 狀態 */ /**沒有硬幣狀態*/ private final static int NO_QUARTER = 0; /**投幣狀態*/ private final static int HAS_QUARTER = 1; /**出售糖果狀態*/ private final static int SOLD = 2; /**糖果售盡狀態*/ private final static int SOLD_OUT = 3; private int state = SOLD_OUT; private int candyCount = 0; public NoPatternGumballMachine(int count) { this.candyCount = count; if(candyCount > 0) state = NO_QUARTER; } /* * 四個(ge) 動作 */ /** * 投幣 */ public void insertQuarter() { if(NO_QUARTER == state){ System.out.println("投幣"); state = HAS_QUARTER; } else if(HAS_QUARTER == state){ System.out.println("請不要重複投幣!"); returnQuarter(); } else if(SOLD == state){ System.out.println("已投幣,請等待糖果"); returnQuarter(); }else if(SOLD_OUT == state){ System.out.println("糖果已經售盡"); returnQuarter(); } } /** * 退幣 */ public void ejectQuarter() { if(NO_QUARTER == state){ System.out.println("沒有硬幣,無法彈出"); } else if(HAS_QUARTER == state){ returnQuarter(); state = NO_QUARTER; } else if(SOLD == state){ System.out.println("無法退幣,正在發放糖果,請等待"); }else if(SOLD_OUT == state){ System.out.println("沒有投幣,無法退幣"); } } /** * 轉動出糖曲軸 */ public void turnCrank() { if(NO_QUARTER == state){ System.out.println("請先投幣"); } else if(HAS_QUARTER == state){ System.out.println("轉動曲軸,準備發糖"); state = SOLD; } else if(SOLD == state){ System.out.println("已按過曲軸,請等待"); }else if(SOLD_OUT == state){ System.out.println("糖果已經售盡"); } } /** * 發糖 */ public void dispense() { if(NO_QUARTER == state){ System.out.println("沒有投幣,無法發放糖果"); } else if(HAS_QUARTER == state){ System.out.println("this method don't support"); } else if(SOLD == state){ if(candyCount > 0){ System.out.println("分發一顆糖果"); candyCount --; state = NO_QUARTER; } else{ System.out.println("抱歉,糖果已售盡"); state = SOLD_OUT; } }else if(SOLD_OUT == state){ System.out.println("抱歉,糖果已售盡"); } } /** * 退還硬幣 */ protected void returnQuarter() { System.out.println("退幣……"); } } //改造後 //1、定義(yi) 一個(ge) 接口或者抽象類,抽象出幾個(ge) 行為(wei) 狀態 public abstract class State { /** * 投幣 */ public abstract void insertQuarter(); /** * 退幣 */ public abstract void ejectQuarter(); /** * 轉動出糖曲軸 */ public abstract void turnCrank(); /** * 發糖 */ public abstract void dispense(); /** * 退還硬幣 */ protected void returnQuarter() { System.out.println("退幣……"); } } // 2、為(wei) 每個(ge) 狀態實現接口或基類 /** * 沒有硬幣的狀態 */ public class NoQuarterState extends State{ GumballMachine gumballMachine; public NoQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } @Override public void insertQuarter() { System.out.println("你投入了一個(ge) 硬幣"); //轉換為(wei) 有硬幣狀態 gumballMachine.setState(gumballMachine.hasQuarterState); } @Override public void ejectQuarter() { System.out.println("沒有硬幣,無法彈出"); } @Override public void turnCrank() { System.out.println("請先投幣"); } @Override public void dispense() { System.out.println("沒有投幣,無法發放糖果"); } } /** * 投硬幣的狀態 */ public class HasQuarterState extends State{ GumballMachine gumballMachine; public HasQuarterState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } @Override public void insertQuarter() { System.out.println("請不要重複投幣!"); returnQuarter(); } @Override public void ejectQuarter() { returnQuarter(); gumballMachine.setState(gumballMachine.noQuarterState); } @Override public void turnCrank() { System.out.println("轉動曲軸,準備發糖"); gumballMachine.setState(gumballMachine.soldState); } @Override public void dispense() { System.out.println("this method don't support"); } } /** * 出售的狀態 */ public class SoldState extends State{ GumballMachine gumballMachine; public SoldState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } @Override public void insertQuarter() { System.out.println("已投幣,請等待糖果"); returnQuarter(); } @Override public void ejectQuarter() { System.out.println("無法退幣,正在發放糖果,請等待"); } @Override public void turnCrank() { System.out.println("已按過曲軸,請等待"); } @Override public void dispense() { int candyCount = gumballMachine.getCandyCount(); if(candyCount > 0){ System.out.println("分發一顆糖果"); candyCount--; gumballMachine.setCandyCount(candyCount); if(candyCount > 0){ gumballMachine.setState(gumballMachine.noQuarterState); return; } } System.out.println("抱歉,糖果已售盡"); gumballMachine.setState(gumballMachine.soldOutState); } } /** * 售盡的狀態 */ public class SoldOutState extends State{ GumballMachine gumballMachine; public SoldOutState(GumballMachine gumballMachine) { this.gumballMachine = gumballMachine; } @Override public void insertQuarter() { System.out.println("糖果已經售盡"); returnQuarter(); } @Override public void ejectQuarter() { System.out.println("沒有投幣,無法退幣"); } @Override public void turnCrank() { System.out.println("糖果已經售盡"); } @Override public void dispense() { System.out.println("糖果已經售盡"); } } //3、將糖果機的動作委托到狀態類 public class GumballMachine extends State{ public State noQuarterState = new NoQuarterState(this); public State hasQuarterState = new HasQuarterState(this); public State soldState = new SoldState(this); public State soldOutState = new SoldOutState(this); private State state = soldOutState; private int candyCount = 0; public GumballMachine(int count) { this.candyCount = count; if(count > 0) setState(noQuarterState); } @Override public void insertQuarter() { state.insertQuarter(); } @Override public void ejectQuarter() { state.ejectQuarter(); } @Override public void turnCrank() { state.turnCrank(); } @Override public void dispense() { state.dispense(); } public void setState(State state) { this.state = state; } public State getState() { return state; } public void setCandyCount(int candyCount) { this.candyCount = candyCount; } public int getCandyCount() { return candyCount; } }
從(cong) 代碼裏麵可以看出,糖果機根據此刻不同的狀態,而使對應的動作呈現不同的結果。這份代碼已經可以滿足我們(men) 的基本需求,但稍微思考一下,你會(hui) 覺得這種實現代碼似乎,功能太複雜了,擴展性很差,沒有麵向對象的風格。
假設由於(yu) 新需求,要增加一種狀態,那每個(ge) 動作方法我們(men) 都需要修改,都要重新增加一條else語句。而如果需求變更,某個(ge) 狀態下的動作需要修改,我們(men) 也要同時改動四個(ge) 方法。這樣的工作將是繁瑣而頭大的。
可以發現,這種模式下,糖果機根本不需要清楚狀態的改變,它隻用調用狀態的方法就行。狀態的改變是在狀態內(nei) 部發生的。這就是"狀態模式"。
如果此時再增加一種狀態,糖果機不需要做任何改變,我們(men) 隻需要再增加一個(ge) 狀態類,然後在相關(guan) 的狀態類方法裏麵增加轉換的過程即可
-
除常用方法(如 getXxx/isXxx)等外,不要在條件判斷中執行其它複雜的語句,將複雜邏輯判斷的結果賦值給一個(ge) 有意義(yi) 的布爾變量名,以提高可讀性。
說明:很多 if 語句內(nei) 的邏輯相當複雜,閱讀者需要分析條件表達式的最終結果,才能明確什麽(me) 樣的條件執行什麽(me) 樣的語句,那麽(me) ,如果閱讀者分析邏輯表達式錯誤呢?
正例: // 偽(wei) 代碼如下 final boolean existed = (file.open(fileName, "w") != null) && (...) || (...); if (existed) { ... } 反例: if ((file.open(fileName, "w") != null) && (...) || (...)) { ... }
(八)注釋規範
-
類、類屬性、類方法的注釋必須使用 Javadoc 規範,使用/**內(nei) 容*/格式,不得使用// xxx 方式
-
所有的抽象方法(包括接口中的方法)必須要用 Javadoc 注釋、除了返回值、參數、異常說明外,還必須指出該方法做什麽(me) 事情,實現什麽(me) 功能。
-
方法內(nei) 部單行注釋,在被注釋語句上方另起一行,使用//注釋。方法內(nei) 部多行注釋使用/ /注釋,注意與(yu) 代碼對齊。
-
所有的枚舉(ju) 類型字段必須要有注釋,說明每個(ge) 數據項的用途。
-
代碼修改的同時,注釋也要進行相應的修改,尤其是參數、返回值、異常、核心邏輯等的修改。代碼和注釋要同步更新
-
對於(yu) 注釋的要求:第一、能夠準確反應設計思想和代碼邏輯;第二、能夠描述業(ye) 務含義(yi) ,使別的程序員能夠迅速了解到代碼背後的信息。注釋要盡可能精簡準確、表達到位,要避免過多過濫的注釋。
-
特殊注釋標記,請注明標記人與(yu) 標記時間。注意及時處理這些標記,通過標記掃描,經常清理此類標記。線上故障有時候就是來源於(yu) 這些標記處的代碼。
-
待辦事宜(TODO):( 標記人,標記時間,[預計處理時間])表示需要實現,但目前還未實現的功能。這實際上是一個(ge) Javadoc 的標簽,目前的 Javadoc還沒有實現,但已經被廣泛使用。隻能應用於(yu) 類,接口和方法(因為(wei) 它是一個(ge) Javadoc 標簽)。
-
錯誤,不能工作(FIXME):(標記人,標記時間,[預計處理時間])在注釋中用 FIXME 標記某代碼是錯誤的,而且不能工作,需要及時糾正的情況。
(九)其他
-
獲取當前毫秒數 System.currentTimeMillis(); 而不是 new Date().getTime();說明:如果想獲取更加精確的納秒級時間值,使用 System.nanoTime()的方式。在 JDK8 中,針對統計時間等場景,推薦使用 Instant 類
-
不要在controller層加任何複雜的邏輯
-
任何數據結構的構造或初始化,都應指定大小,避免數據結構無限增長吃光內(nei) 存
-
一個(ge) 方法體(ti) 不要過長,要對邏輯進行拆分,盡量不要超過80行