一位攻城獅的自我修養(yǎng),在于良好的編程規(guī)范

下載.jpeg

命名風(fēng)格

  • 類名使用UpperCamelCase風(fēng)格,但下列情形除外:
    • DO: Data Object. 與數(shù)據(jù)庫表結(jié)構(gòu)一一對(duì)應(yīng),通過DAO層向上傳輸數(shù)據(jù)源對(duì)象
    • BO: Business Object,業(yè)務(wù)對(duì)象. 由Service層輸出的封裝業(yè)務(wù)邏輯的對(duì)象
    • DTO: Data Transfer Object,數(shù)據(jù)傳輸對(duì)象. Service或Manager向外傳輸?shù)膶?duì)象
    • VO: View Object,顯示對(duì)象. 通常是Web向模板渲染引擎層傳輸?shù)膶?duì)象
    • AO: Application Object,應(yīng)用對(duì)象. 在Web層與Service層之間抽象復(fù)用的對(duì)象模型
    • PO: POJO縮寫,Plain Ordinary Java Object. 專指只有setter/getter/toString的簡單類,包括DO,DTO,BO,VO等, 禁止使用xxxPOJO來命名
    • UID
  • 方法名,參數(shù)名,成員變量,局部變量都統(tǒng)一使用lowerCamelcase風(fēng)格
  • 常量命名全部大寫,單詞間用下劃線隔開, 力求語義表達(dá)完整清楚,不要嫌名字長
  • 抽象類命名使用Abstract或者Base開頭
  • 異常類命名使用Exception結(jié)尾
  • 測(cè)試類命名要以要測(cè)試的類的名稱命名,以Test結(jié)尾
  • 類型與中括號(hào)緊挨來表示數(shù)組
  • POJO類中布爾類型的變量都不要加is前綴,在部分框架中會(huì)引起序列化錯(cuò)誤
  • 包名統(tǒng)一使用小寫,點(diǎn)分隔符之間有且僅有一個(gè)自然語義的英語單詞.包名統(tǒng)一使用單數(shù)形式.但是類名如果有復(fù)數(shù)含義,可以使用復(fù)數(shù)形式
  • 杜絕不規(guī)范的縮寫,避免望文不知義
  • 為了達(dá)到代碼自解釋的目標(biāo),任何自定義的編程元素在命名時(shí),使用盡量完整的單詞組合來表達(dá)含義
  • 在常量與變量命名的同時(shí),表示類型的名詞放在詞尾,以提升辨識(shí)度
  • 如果模塊,接口,類,方法使用了設(shè)計(jì)模式,在命名時(shí)需要體現(xiàn)出設(shè)計(jì)模式
  • 接口類中的方法和屬性不要加任何修飾符號(hào)(不要加public), 保持代碼的簡潔
  • 盡量不要在接口中定義變量,如果一定要定義變量,一定是與接口方法有關(guān)的,并且是整個(gè)應(yīng)用的基礎(chǔ)變量
    • 接口方法簽名: void commit()
    • 接口基礎(chǔ)常量: String COMPANY="Oxford"
  • 接口和實(shí)現(xiàn)類:
    • 對(duì)于ServiceDAO類,基于SOA的理念,暴露出來的服務(wù)一定是接口,內(nèi)部的實(shí)現(xiàn)類用Impl的后綴與接口的區(qū)別
    • 如果是形容能力的接口名稱,去對(duì)應(yīng)的形容詞為接口(-able的形式)
  • 枚舉類帶上Enum后綴,枚舉成員名稱需全部大寫
    • 枚舉類是特殊的類,域成員均為常量,且構(gòu)造方法被默認(rèn)強(qiáng)制是私有的
  • 各層命名規(guī)范:
    • Service或者DAO層方法命名規(guī)范:
      • 獲取單個(gè)對(duì)象的方法用get做前綴
      • 獲取多個(gè)對(duì)象的方法用list做前綴 ,復(fù)數(shù)形式結(jié)尾
      • 獲取統(tǒng)計(jì)值的方法用count做前綴
      • 插入方法使用save或者insert做前綴
      • 刪除的方法使用remove或者delete做前綴
      • 修改的方法使用update做前綴
    • 領(lǐng)域模型命名規(guī)范:
      • 數(shù)據(jù)對(duì)象: XxxDO,Xxx為數(shù)據(jù)表名
      • 數(shù)據(jù)傳輸對(duì)象: XxxDTO,Xxx為業(yè)務(wù)領(lǐng)域相關(guān)的名稱
      • 展示對(duì)象: XxxVO,xxx一般為網(wǎng)頁名稱
      • POJO為DO,DTO,BO,VO的統(tǒng)稱,禁止命名成XxxPOJO

常量定義

  • 不允許任何未經(jīng)預(yù)先定義的常量出現(xiàn)在代碼中
  • 在long或者Long賦值時(shí),數(shù)值后使用大寫的L, 不能是小寫的l. 因?yàn)樾懭菀缀蛿?shù)字1混淆,造成誤解
  • 不要使用一個(gè)常量類維護(hù)所有常量,要按常量的功能進(jìn)行歸類,分開維護(hù)
    • 大而全的常量類雜亂無章,使用查找功能才能定位到修改的常量,不利于理解和維護(hù)
  • 常量的復(fù)用層次有五層:
    • 跨應(yīng)用共享常量: 放置在二方庫中,通常是client.jar中的constant目錄下
    • 應(yīng)用類共享常量 放置在一方庫中,通常是子模塊中的constant目錄下
    • 子工程內(nèi)共享常量 在當(dāng)前子工程的constant目錄下
    • 包內(nèi)共享常量 在當(dāng)前包的constant目錄下
    • 類內(nèi)共享常量 直接在類內(nèi)部private static final定義
  • 如果變量值僅在一個(gè)固定范圍內(nèi)變化,使用enum類型定義?
    • 如果存在名稱之外的延伸屬性應(yīng)使用enum類型,比如季節(jié),表示一年中第幾個(gè)季節(jié):
public enum SeasonEnum {
    SPRING(1),SUMMER(2),AUTUMN(3),WINTER(4);
    private int seq;
    SeasonEnum(int seq) {
        this.seq=seq;
    }
} 

代碼格式

  • 大括號(hào)的使用約定:
    • 如果大括號(hào)內(nèi)為空,則簡潔地寫成 { } 即可,不需要換行
    • 如果是非空代碼塊:
      • 左大括號(hào)前不換行
      • 左大括號(hào)后換行
      • 右大括號(hào)前換行
      • 右大括號(hào)后如果還有else則不換行
      • 表示終止的右大括號(hào)后必須換行
  • 小括號(hào)的使用約定:
    • 左小括號(hào)和字符之間不要出現(xiàn)空格
    • 右小括號(hào)和字符之間也不要出現(xiàn)空格
    • 左大括號(hào)之前需要空格
  • if,for,while,switch,do等保留字與括號(hào)之間都必須加空格
  • 任何二目,三目運(yùn)算符左右兩邊都需要加一個(gè)空格
    • 運(yùn)算符包括:
      • 賦值運(yùn)算符 :=
      • 邏輯運(yùn)算符 :&&
      • 加減乘除符號(hào)
  • 采用4個(gè)空格進(jìn)行縮進(jìn)
  • 注釋的雙斜線與注釋內(nèi)容之間有且僅有一個(gè)空格
  • 方法參數(shù)在定義和傳入時(shí),多個(gè)參數(shù)逗號(hào)后面必須加空格
  • 單個(gè)方法的總行數(shù)不要超過80行:
    • 除注釋之外的方法簽名,左右大括號(hào),方法內(nèi)代碼,空行,回車及任何不可見字符的總行數(shù)不超過80行
    • 代碼邏輯分清紅花和綠葉,個(gè)性和共性:
      • 綠葉邏輯單獨(dú)出來成為額外的方法,使主干代碼更加清晰
      • 共性邏輯抽取成共性方法,便于復(fù)用和維護(hù)
  • 不需要增加若干空格來使某一行的字符與上一行對(duì)應(yīng)位置的字符對(duì)齊
  • 不同邏輯,不同語義,不同業(yè)務(wù)代碼之間只需要插入一個(gè)空行分割來提升可讀性即可

OPP規(guī)約

  • 避免通過一個(gè)類的對(duì)象引用訪問類的靜態(tài)變量和靜態(tài)方法,這會(huì)增加編譯器的解析成本,直接使用類名訪問即可
  • 所有的覆寫方法,必須加 @Override
  • 相同參數(shù)類型,相同業(yè)務(wù)含義,才可以使用Java的可變參數(shù),避免可變參數(shù)使用Object類型
    • 可變參數(shù)必須放置在參數(shù)列表的最后, 建議盡量不要用可變參數(shù)編程
  • 外部正在調(diào)用的或者二方庫依賴的接口,不允許修改方法簽名(方法名和參數(shù)列表),避免對(duì)接口的調(diào)用方產(chǎn)生影響 .接口過時(shí)必須加上 ==@Deprecated== 注解,并清晰地說明采用的新接口和新服務(wù)是什么
  • 不能使用過時(shí)的類或方法:
    • 接口的提供方既然明確是過時(shí)接口,那么有義務(wù)提供新接口
    • 作為調(diào)用方,有義務(wù)考證過時(shí)方法的新實(shí)現(xiàn)是什么
  • Objectequals方法容易拋出空指針異常,應(yīng)使用常量或者確定有值的對(duì)象來調(diào)用equals
    • "test".equals(Object)
    • 推薦使用java.util.objects
  • 所有相同類型的包裝類對(duì)象之間的值的比較,全部使用equals方法比較
    • 對(duì)于 Integer var = ? 在-128至127范圍內(nèi)賦值時(shí) ,Integer對(duì)象是在IntegerCache.cache中產(chǎn)生,會(huì)復(fù)用已有對(duì)象,這個(gè)區(qū)間內(nèi)的Integer值可以直接使用 == 進(jìn)行判斷
    • 但是這個(gè)區(qū)間之外的所有數(shù)據(jù),都會(huì)在堆上產(chǎn)生,并不會(huì)復(fù)用已有對(duì)象,所以推薦使用equals方法進(jìn)行比較
  • 任何貨幣金額,均以最小貨幣單位且整型類型來進(jìn)行存儲(chǔ)
  • 浮點(diǎn)數(shù)之間的等值判斷:
    • 基本類型不能用 == 來比較
    • 包裝類型不能使用equals來判斷
      • 浮點(diǎn)數(shù)采用尾數(shù)+階碼的編碼方式,類似與科學(xué)計(jì)數(shù)法有效數(shù)字+指數(shù)的表示方式. 二進(jìn)制無法精確表示大部分十進(jìn)制小數(shù)
    • 為了避免出現(xiàn)問題,所有的浮點(diǎn)數(shù)都使用BigDecimal定義
/*
 * float類型的浮點(diǎn)數(shù):
 *      指定一個(gè)誤差范圍,
 *      兩個(gè)浮點(diǎn)數(shù)的差值在此范圍之內(nèi),
 *      則認(rèn)為是相等的.
 */
 float a = 1.0f - 0.9f;
 float b = 0.9f - 0.8f;
 float diff = 1e - 6f;
 if (Math.abs(a-b) < diff) {
    System.out.println("true");
 }

/* 
 *  使用BigDecimal來定義值,再進(jìn)行浮點(diǎn)數(shù)的運(yùn)算操作
 */
 BigDecimal a = new BigDecimal("1.0");
 BigDecimal b = new BigDecimal("0.9");
 BigDecimal c = new BigDecimal("0.8");
 BigDecimal x = a.substract(b); 
 BigDecimal y = b.substract(c);
 if (x.equals(y)) {
    System.out.println("true");
 } 
  • 定義數(shù)據(jù)對(duì)象DO類時(shí),屬性類型要與數(shù)據(jù)庫字段類型相匹配
    • 數(shù)據(jù)庫字段的bigint必須與類屬性Long類型相對(duì)應(yīng)
  • 禁止使用構(gòu)造方法BigDecimal(double) 的方式將double值轉(zhuǎn)化為BigDecimal對(duì)象:
    • BigDecimal(double)存在精度損失風(fēng)險(xiǎn),在精確計(jì)算或值比較的場(chǎng)景中會(huì)導(dǎo)致業(yè)務(wù)邏輯異常
      • 推薦使用入?yún)?strong>String的構(gòu)造方法
      • 或者使用BigDecimalvalueOf方法: 此方法內(nèi)部執(zhí)行了Double的toString,實(shí)際能表達(dá)的精度對(duì)尾數(shù)進(jìn)行了截?cái)?/li>
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = BigDecimal.valueOf(0.1);
  • 基本類型和包裝類型的使用標(biāo)準(zhǔn):
    • 所有的POJO類屬性必須使用包裝類數(shù)據(jù)類型
    • RPC方法的返回值和參數(shù)必須使用包裝數(shù)據(jù)類型
    • 所有的局部變量使用基本數(shù)據(jù)類型
  • 定義DO,DTO,VO等POJO類時(shí),不要設(shè)定任何屬性默認(rèn)值
  • 序列化類新增屬性時(shí),不能修改serialVersionUID字段,這樣會(huì)導(dǎo)致反序列化失敗;如果完全不兼容升級(jí),避免反序列化混亂,可以修改serialVersionUID值.在serialVersionUID不一致時(shí)會(huì)拋出序列化運(yùn)行時(shí)異常
  • 構(gòu)造方法中禁止加入任何業(yè)務(wù)邏輯,如果有初始化邏輯,要放在init
  • POJO類必須寫toString方法.如果繼承了一個(gè)POJO類,需要在前面添加super.toString
    • 這樣在方法執(zhí)行拋出異常時(shí),可以直接調(diào)用POJO的toString()方法打印屬性值,便于排查問題
  • 禁止在POJO類中,同時(shí)存在對(duì)應(yīng)屬性Xxx的isXxx()getXxx() 方法
    • 框架在調(diào)用屬性Xxx的獲取方法時(shí),不能確定哪個(gè)方法一定是被優(yōu)先調(diào)用到的
  • 使用索引訪問用String的split方法得到的數(shù)組時(shí),需要做最后一個(gè)分隔符后有無內(nèi)容的檢查, 否則會(huì)有IndexOutofBoundsException異常
  • 當(dāng)一個(gè)類有多個(gè)構(gòu)造方法,或者多個(gè)同名方法,這些方法應(yīng)該按順序放置在一起,便于閱讀
  • 類內(nèi)方法定義的順序依次為:
    • 公有方法或者保護(hù)方法
      • 公有方法是類調(diào)用者或者維護(hù)最頻繁使用的方法,最好首先展示
      • 保護(hù)方法盡管是子類需要的方法,但也可能是模板設(shè)計(jì)模式中的核心方法
    • 私有方法
      • 私有方法外部一般不需要關(guān)心,是一個(gè)黑盒實(shí)現(xiàn)
    • getter或者setter方法
      • 所有Service和DAO的getter或者setter方法都放在類的最后
  • setter方法中,參數(shù)名稱要和類成員變量名稱一致 ,this.成員名=參數(shù)名.
  • 在getter或者setter方法中,不要增加業(yè)務(wù)邏輯
  • 循環(huán)體內(nèi),字符串的類連接方式,使用StringBuilderappend方法進(jìn)行擴(kuò)展
    • 否則會(huì)導(dǎo)致每次循環(huán)都會(huì)new一個(gè)新的StringBuilder對(duì)象
    • 然后再進(jìn)行append操作
    • 最后通過toString方法返回String對(duì)象,造成資源浪費(fèi)
  • final可以聲明類,成員變量,方法,以及本地變量. 使用final的情況:
    • 不允許被繼承的類
      • String
    • 不允許修改的引用的域?qū)ο?/strong>
    • 不允許被重寫的方法
      • POJO中的setter方法
    • 不允許運(yùn)行過程中重新賦值的局部變量
    • 避免上下文重復(fù)使用一個(gè)變量,使用final描述可以強(qiáng)制重新定義,方便更好地進(jìn)行重構(gòu)
  • 不要使用Objectclone方法拷貝對(duì)象:
    • 對(duì)象的clone方法默認(rèn)是淺拷貝
    • 若想實(shí)現(xiàn)深度拷貝需要重寫clone方法實(shí)現(xiàn)域?qū)ο蟮纳疃缺闅v拷貝需要重寫clone方法實(shí)現(xiàn)域?qū)ο蟮纳疃缺闅v拷貝
  • 類成員與方法訪問控制規(guī)約:
    • 如果不允許外部直接通過new來創(chuàng)建對(duì)象,那么構(gòu)造方法必須是private
    • 工具類不允許有public或者default構(gòu)造方法
    • 類非static成員變量并且與子成員共享,必須是protected
    • 類非static成員變量并且僅在本類中使用,必須是private
    • 類static成員變量如果僅在本類中使用,必須是private
    • 若是static成員變量,考慮是否為final
    • 類成員方法只供類內(nèi)部調(diào)用時(shí),必須是private
    • 類成員方法只對(duì)繼承類公開時(shí),限制使用protected

日期時(shí)間

  • 日期格式化時(shí),傳入pattern中表示年份統(tǒng)一使用小寫的yyyy
    • 日期格式化時(shí):
      • yyyy表示當(dāng)天所在的年
      • YYYY表示當(dāng)天所在的周屬于的年份,一周從周日開始,至周六結(jié)束.如果本周跨年,返回的YYYY就是下一年
  • 在日期格式中分清楚大寫的M和小寫的m,大寫的H和小寫的h的含義:
    • 表示月份的是大寫的M
    • 表示分鐘的是小寫的m
    • 24小時(shí)的是大寫的H
    • 12小時(shí)的是小寫的h
  • 獲取當(dāng)前的毫秒數(shù) :System.currentTimeMillis()
    • 如果想要獲取更加精確的納秒級(jí)的時(shí)間值,使用System.nanoTime()
    • 針對(duì)統(tǒng)計(jì)時(shí)間的場(chǎng)景,推薦使用Instant
  • 不要使用java.sql中的相關(guān)時(shí)間方法
  • 不要在程序中寫死一年的為365,避免在公歷閏年時(shí)出現(xiàn)日期轉(zhuǎn)換錯(cuò)誤或程序邏輯錯(cuò)誤
    • 使用LocalDate方法
// 獲取今年的天數(shù)
int daysOfThisYear = LocalDate.now().lengthOfYear();

// 獲取指定某年的天數(shù)
LocalDate.of(2011, 1, 1).lengthOfYear();
  • 使用Calendar中的枚舉值來指代月份
    • 如果使用數(shù)字,要注意Date,Calendar等日期相關(guān)類的月份month的值在0 - 11之間

集合處理

  • hashCode和equals的處理:
    • 只要重寫equals, 就必須重寫hashCode
    • Set中存儲(chǔ)的是不重復(fù)的對(duì)象,依據(jù)hashCodeequals進(jìn)行判斷,所以Set存儲(chǔ)的對(duì)象必須重寫這兩個(gè)方法
    • 如果自定義對(duì)象作為Map的鍵,必須重寫hashCodeequals
      • String重寫了hashCodeequals方法所以可以使用String對(duì)象作為key來使用
  • ArrayList的subList結(jié)果不可以強(qiáng)轉(zhuǎn)成ArrayList,否則會(huì)拋出ClassCastException異常:
    • subList返回的是ArrayList的內(nèi)部類SubList, 并不是ArrayList, 而是ArrayList的一個(gè)視圖.對(duì)于SubList子列表的所有操作最終會(huì)反映到原列表上
  • 在subList場(chǎng)景中,要注意對(duì)原集合元素的增加或者刪除,都會(huì)導(dǎo)致子列表的遍歷,增加和刪除產(chǎn)生ConcurrentModificationException異常
  • 使用Map的方法:
    • keySet()
    • values()
    • entrySet()
    • 返回集合對(duì)象時(shí),不可以進(jìn)行添加元素的操作,否則會(huì)拋出UnsupportedOperationException異常
  • Collections類返回的對(duì)象不可以進(jìn)行添加或者刪除操作:
    • 如果查詢無結(jié)果,則返回Collection.emptyList()空集合對(duì)象. 調(diào)用方一旦進(jìn)行了添加元素操作,就會(huì)觸發(fā)UnsupportedOperationException異常
  • 使用集合轉(zhuǎn)數(shù)組的方法,必須使用集合的 toArrary(T[] array), 傳入的是類型完全一樣的數(shù)組,數(shù)組的大小就是list.size()
    • 使用toArray帶參方法,入?yún)⒎峙涞臄?shù)組空間不夠大時(shí),toArray方法內(nèi)部將重新分配內(nèi)存空間,并返回新數(shù)組的地址;
    • 如果數(shù)組元素個(gè)數(shù)大于實(shí)際所需,下標(biāo)為[list.size()] 的元素的數(shù)組元素將被置為null,其余數(shù)組元素保持原值
    • 因此最好將方法入?yún)?shù)組大小定義為與集合元素個(gè)數(shù)一致
List<String> list = new ArrayList<>();
list.add("guan");
list.add("bao");
String[] array = new String[list.size];
array = list.toArray(array);
  • 在使用Collection接口任何實(shí)現(xiàn)類的addAll() 方法時(shí),都要對(duì)輸入集合參數(shù)進(jìn)行NPE判斷
  • 使用工具類Arrays.asList()將數(shù)組轉(zhuǎn)換成集合時(shí),不能使用這個(gè)相關(guān)的修改集合的方法,這個(gè)集合的add, remove, clear方法會(huì)拋出UnsupportedOperationException異常
    • asList的返回對(duì)象是一個(gè)Arrays內(nèi)部類,并沒有實(shí)現(xiàn)集合的修改方法
    • Arrays.asList體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺(tái)數(shù)據(jù)依舊是數(shù)組
  • 泛型通配符 <? extends T> 來接收返回的數(shù)據(jù),這種寫法的泛型集合不能使用add方法 ;<? super T> 不能使用get方法,作為接口調(diào)用賦值時(shí)會(huì)出錯(cuò)
    • PECS(Producer Extends Consumer Super)原則:
      • 頻繁往外讀取內(nèi)容,適合使用<? extends T>
      • 經(jīng)常往里插入的,適合使用<? super T>
  • 不要在foreach循環(huán)里進(jìn)行元素的remove或者add操作
    • remove元素要使用Iterator方式,如果是并發(fā)操作,要對(duì)Iterator對(duì)象加鎖
List<String> list = new ArrayList<>();
list.add("1");
list.add("2");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if (condition) {
        iterator.remove();
    }
}
  • JDK 7以后的版本中 ,Comparator實(shí)現(xiàn)要滿足三個(gè)條件,否則Arrays.sort, Collections.sort會(huì)出現(xiàn)IllegalArgumentException異常:
    • x, y的比較結(jié)果和y, x的比較結(jié)果相反
    • x > y, y > z, 則 x > z
    • x = y, 則x, z比較結(jié)果和y, z比較結(jié)果相同
  • JDK 7以后的版本中,給集合的泛型定義時(shí),使用全省略,即直接使用 <> 來指定前邊已經(jīng)指定的類型
  • 集合初始化時(shí),指定集合初始值大小
    • HashMap使用HashMap(int initialCapacity) 初始化
    • initalCapacity = (需要存儲(chǔ)的元素個(gè)數(shù) / 負(fù)載因子) + 1. 注意負(fù)載因子(即loader factor)默認(rèn)為0.75,如果暫時(shí)無法確定初始值的大小,設(shè)為為默認(rèn)值16
  • 使用entrySet遍歷Map類集合kv, 而不是使用keySet方式進(jìn)行遍歷
    • 如果使用keySet方式遍歷,其實(shí)是遍歷了兩次:
      • 一次轉(zhuǎn)換為Iterator對(duì)象
      • 一次從hashMap中取出key所對(duì)應(yīng)的value
    • entrySet只是遍歷一次就把keyvalue都放到了entry中,效率更高
    • 如果是JDK 8以后的版本,使用Map.foreach方法
    • 示例:
      • values()返回的是V值集合,是一個(gè)list集合對(duì)象
      • keySet()返回的是K值集合,是一個(gè)Set集合對(duì)象
      • entrySet()返回的是K-V值組合集合
  • 要注意Map類集合中的K-V能不能存儲(chǔ)null值的情況:
集合類 Key Value Super 說明
Hashtable 不允許為null 不允許為null Dictionary 線程安全
ConcurrentHashMap 不允許為null 不允許為null AbstractMap 鎖分段技術(shù)
TreeMap 不允許為null 允許為null AbstractMap 線程不安全
HashMap 允許為null 允許為null AbstractMap 線程不安全

由于HashMap的干擾,誤以為ConcurrentHashMap可以置入null值,其實(shí)這樣會(huì)拋出NPE異常

  • 合理利用集合的有序型 - sort和集合的穩(wěn)定性 - order, 避免集合的無序性 - unsort和不穩(wěn)定性 - unorder帶來的負(fù)面影響
    • 有序性是指遍歷的結(jié)果按照某種比較規(guī)則依次排列的
    • 穩(wěn)定性是指集合每次遍歷的元素次序是一定的
    • ArrayList, HashMap, TreeSet
  • 利用Set元素唯一的特性,可以快速對(duì)一個(gè)集合進(jìn)行去重操作
    • 避免使用List的contains方法進(jìn)行遍歷,對(duì)比,去重操作

并發(fā)處理

  • 獲取單例對(duì)象需要保證線程安全,其中的方法也要保證線程安全
    • 資源驅(qū)動(dòng)類, 工具類, 單例工廠類都需要注意
  • 創(chuàng)建線程或者線程池時(shí)要指定有意義的線程名稱,方便出錯(cuò)時(shí)回溯
  • 線程資源必須通過線程池提供,不允許在應(yīng)用中自行顯式創(chuàng)建線程
    • 使用線程池的好處是減少在創(chuàng)建和銷毀線程上所消耗的時(shí)間以及系統(tǒng)資源的開銷,解決資源不足的問題
    • 如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量同類線程而導(dǎo)致消耗完內(nèi)存或者過度切換的問題
  • 線程池不允許使用Executors創(chuàng)建,要通過ThreadPoolExecutors創(chuàng)建,這樣可以讓人更加明確線程池的運(yùn)行規(guī)則,規(guī)避資源消耗的風(fēng)險(xiǎn)
    • Executors返回線程池對(duì)象存在以下問題:
      • FixedThreadPool和SingleThreadPool:
        • 允許請(qǐng)求隊(duì)列長度為Integer.MAX_VALUE,可能會(huì)堆積大量請(qǐng)求,導(dǎo)致OOM
      • CachedThreadPool和ScheduledThreadPool:
        • 允許創(chuàng)建的線程數(shù)量為Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量線程,導(dǎo)致OOM
  • SimpleDateFormat是線程不安全類,不要定義為static變量.如果定義為static,必須加鎖,或者使用DateUtils工具類
    • 注意線程安全,使用DateUtils,可以進(jìn)行如下處理:
    private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
      @Override
      protected DateFormat initialValue() {
          return new SimpleDateFormat("yyyy-MM-dd");
      }
    }
    
    • 在JDK 8中,可以使用:
      • Instant 代替 Date
      • LocalDateTime 代替 Calendar
      • DateTimeFormatter 代替 SimpleDateFormat
  • 必須回收自定義的ThreadLocal變量:
    • 尤其在線程池場(chǎng)景下,線程經(jīng)常會(huì)被復(fù)用,如果不清理自定義的ThreadLocal變量,會(huì)影響后續(xù)業(yè)務(wù)邏輯和造成內(nèi)存泄漏的問題
    • 盡量在代理中使用try - finally塊進(jìn)行回收
ObjectThreadLocal.set(userInfo);
try {
    ...
} finally {
    ObjectThreadLocal.remove();
} 
  • 高并發(fā)時(shí),同步調(diào)用應(yīng)該考量鎖的性能損耗.
    • 能用無鎖數(shù)據(jù)結(jié)構(gòu),就不要用鎖
    • 能用鎖區(qū)塊,就不要鎖整個(gè)方法體
    • 能用對(duì)象鎖,就不要用類鎖
      • 盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調(diào)用RPC方法
  • 對(duì)多個(gè)資源, 數(shù)據(jù)庫表, 對(duì)象同時(shí)加鎖時(shí),需要保持一致的加鎖順序,否則可能會(huì)造成死鎖
    • 如果線程一需要對(duì)A, B, C依次全部加鎖后才可以進(jìn)行更新操作
    • 那么線程二的加鎖順序也必須是A, B, C.否則可能會(huì)出現(xiàn)死鎖
  • 在使用阻塞等待獲取鎖的方式中:
    • 必須在try代碼塊之外
      • 如果lock方法在try代碼塊之內(nèi),可能由于其它方法拋出異常 ,導(dǎo)致在finally代碼塊中 ,unlock對(duì)未加鎖的對(duì)象解鎖,會(huì)調(diào)用AQStryRelease方法,拋出IlleagalMonitorStateException異常
    • 必須在加鎖方法與try代碼塊之間沒有任何可能拋出異常的方法調(diào)用,避免加鎖成功后,在finally中無法解鎖
      • 如果在lock方法與try代碼塊之間的方法調(diào)用拋出異常,那么無法解鎖,造成其它線程無法獲取鎖
    • Lock對(duì)象的lock方法實(shí)現(xiàn)中可能拋出unchecked異常,導(dǎo)致unlock對(duì)未加鎖的對(duì)象解鎖,會(huì)調(diào)用AQStryRelease方法,拋出IlleagalMonitorStateException異常
Lock lock = new XxxLock();
lock.lock();
try {
    ...
} finally {
    lock.unlock();
}
  • 在使用嘗試機(jī)制來獲取鎖的方式中:
    • 進(jìn)入業(yè)務(wù)代碼之前,必須先判斷當(dāng)前線程是否持有鎖
    • 鎖的釋放規(guī)則與鎖阻塞等待的方式相同
      • Lock對(duì)象的unlock方法在執(zhí)行時(shí),會(huì)調(diào)用AQStryRelease方法,如果當(dāng)前線程不持有鎖, 則拋出IllegalMonitorStateException異常
Lock lock = new XxxLock();
boolean isLocked = lock.tryLock();
if (isLocked) {
    try {
        ...
    } finally {
        lock.unlock();
    }
}
  • 并發(fā)修改同一記錄時(shí),避免更新丟失,需要加鎖:
    • 在應(yīng)用層加鎖
    • 在緩存加鎖
    • 在數(shù)據(jù)庫中加鎖
    • 使用version作為更新依據(jù)
      • 如果每次訪問概率小于20%, 推薦使用樂觀鎖
      • 否則的話,使用悲觀鎖
      • 樂觀鎖的重試次數(shù)不得小于3
  • 多線程并行處理定時(shí)任務(wù)時(shí):
    • Timer運(yùn)行多個(gè)TimerTask時(shí)只要其中之一沒有捕獲拋出的異常,任務(wù)便會(huì)自動(dòng)終止運(yùn)行
    • 使用ScheduleExecutorService則沒有這個(gè)問題
  • 悲觀鎖遵循一鎖二判三更新四釋放的原則
  • 使用CountDownLatch進(jìn)行異步轉(zhuǎn)同步操作:
    • 每個(gè)線程退出前必須調(diào)用countDown方法
    • 線程執(zhí)行代碼注意catch異常,確保counDown方法被執(zhí)行到
    • 避免主線程無法執(zhí)行至await方法,直到超時(shí)才返回結(jié)果
      • 子線程拋出的異常堆棧,不能在主線程try-catch得到異常
  • 避免Random實(shí)例被多線程使用,共享該實(shí)例是線程安全的,但是會(huì)因?yàn)楦?jìng)爭(zhēng)同一個(gè)seed導(dǎo)致性能下降
    • Random實(shí)例:
      • java.util.Random的實(shí)例
      • Math.random() 的方式
    • 在JDK 7后,可以直接使用ThreadLoalRandom
  • 在并發(fā)的場(chǎng)景下,通過雙重檢查鎖double-check locking實(shí)現(xiàn)延遲初始化來優(yōu)化問題隱患:
    • 將目標(biāo)屬性聲明為volatile
  • volatile用于解決多線程內(nèi)存不可見問題:
    • 對(duì)于一寫多讀,可以解決變量同步問題
    • 對(duì)于多寫,無法解決線程安全問題
    • 對(duì)于count++操作,使用如下的類實(shí)現(xiàn):
    AtomicInteger count = new AtomicInteger();
    count.addAndGet(1);
    
    • 在JDK 8后,推薦使用LongAdder對(duì)象,比AtomicLong性能更好,因?yàn)榭梢詼p少樂觀鎖的重試次數(shù)
  • HashMap在容量不夠進(jìn)行resize操作時(shí)會(huì)由于高并發(fā)可能出現(xiàn)死鎖,導(dǎo)致CPU增加:
    • 使用其它的數(shù)據(jù)結(jié)構(gòu)
    • 加鎖
  • ThreadLocal無法解決共享對(duì)象的更新問題,建議要使用static進(jìn)行修飾:
    • 這個(gè)變量是針對(duì)一個(gè)線程內(nèi)所有操作共享的
    • 因此設(shè)置為靜態(tài)變量,所有的此類實(shí)例共享此靜態(tài)變量
    • 即這個(gè)變量在類第一次被使用時(shí)裝載,只分配一塊內(nèi)存空間,只要這個(gè)線程內(nèi)定義的所有此類的對(duì)象都可以操作這個(gè)變量

控制語句

  • 在一個(gè)switch塊內(nèi):
    • 每個(gè)case要通過break或者return來終止
    • 或者注釋說明程序?qū)⒗^續(xù)執(zhí)行到哪一個(gè)case為止
    • 必須包含一個(gè)default語句并且放在最后,即使是空代碼
  • 當(dāng)Switch括號(hào)內(nèi)的變量類型為String并且此變量為外部參數(shù)時(shí),必須進(jìn)行null判斷
  • if, else, for, while, do語句中必須使用大括號(hào),即使只有一行代碼,避免采用單行編碼模式
  • 三目運(yùn)算符: condition ? 表達(dá)式1 : 表達(dá)式2 要注意表達(dá)式1和表達(dá)式2在類型對(duì)齊時(shí),可能因自動(dòng)拆箱導(dǎo)致NPE異常
    • 觸發(fā)類型對(duì)齊的拆箱操作:
      • 表達(dá)式1或者表達(dá)式2只要有一個(gè)原始類型
      • 表達(dá)式1或者表達(dá)式2類型不一致,會(huì)強(qiáng)制拆箱升級(jí)成表示范圍更大的那個(gè)類型
  • 在高并發(fā)的場(chǎng)景中,避免使用 “等于” 判斷作為中斷或者退出的條件
    • 因?yàn)槿绻l(fā)控制沒有處理好,容易產(chǎn)生等值判斷被 “擊穿” 的情況 .要使用大于或者小于區(qū)間判斷條件來代替
    • 示例: 判斷剩余數(shù)量等于0時(shí),當(dāng)數(shù)量等于0的過程中,由于并發(fā)處理錯(cuò)誤導(dǎo)致數(shù)量瞬間變成了負(fù)數(shù),這樣的話,處理無法終止
  • 表達(dá)異常的分支時(shí),不要使用if - else方式,改寫為
if (condition) {
    ...
    return obj;
}
// 然后寫else的業(yè)務(wù)處理邏輯

對(duì)于超過3層的if - else的邏輯判斷代碼可以使用衛(wèi)語句,策略模式,狀態(tài)模式等實(shí)現(xiàn)

  • 除常用的方法 :getXxx, isXxx等,不要在條件判斷中執(zhí)行復(fù)雜的語句,將復(fù)雜邏輯判斷的結(jié)果賦值給一個(gè)有意義的布爾變量名,以提高可讀性
    • 很多if語句內(nèi)的邏輯相當(dāng)復(fù)雜,需要分析表達(dá)式的最終結(jié)果,才能明確什么樣的條件執(zhí)行什么樣的語句
  • 不要在其它表達(dá)式中(尤其時(shí)條件表達(dá)式),插入賦值語句
  • 循環(huán)體中的語句要考量性能,以下操作盡量移動(dòng)至循環(huán)體外處理:
    • 定義對(duì)象,變量
    • 獲取數(shù)據(jù)庫連接
    • 進(jìn)行不必要的try - catch操作(考慮這個(gè)try - catch操作是否可以移動(dòng)至循環(huán)體外)
  • 避免使用取反邏輯運(yùn)算符
    • 取反邏輯運(yùn)算符不利于快速理解
    • 取反邏輯寫法必然存在對(duì)應(yīng)的正向邏輯寫法
  • 接口入?yún)⒈Wo(hù): 這種場(chǎng)景常見的是用作批量操作的接口
  • 參數(shù)校驗(yàn):
    • 需要進(jìn)行參數(shù)校驗(yàn)的情形:
      • 調(diào)用頻次低的方法
      • 執(zhí)行時(shí)間開銷很大的方法
        • 此情形中,參數(shù)校驗(yàn)的時(shí)間幾乎可以忽略不計(jì)
        • 但是如果因?yàn)閰?shù)錯(cuò)誤導(dǎo)致中間執(zhí)行被退回,或者錯(cuò)誤,就得不償失
      • 需要極高穩(wěn)定性和可用性的方法
      • 對(duì)外提供開放接口,無論是 RPC, API, HTTP接口
      • 敏感權(quán)限入口
    • 不需要進(jìn)行參數(shù)校驗(yàn)的情形:
      • 極有可能被循環(huán)調(diào)用的方法. 但是在方法說明里必須注明外部參數(shù)的檢查要求
      • 底層調(diào)用頻度比較高的方法
      • 被聲明成private只會(huì)被自己代碼所調(diào)用的方法.如果能夠確定調(diào)用方法的代碼傳入?yún)?shù)已經(jīng)做過檢查或者肯定不會(huì)有問題,此時(shí)可以不校驗(yàn)參數(shù)

注釋規(guī)約

  • 類, 類屬性, 類方法的注釋必須使用Javadoc規(guī)范,使用/** xxx */格式,不允許使用// xxx方式
  • 所有抽象方法, 包括接口中的方法, 都必須使用Javadoc注釋,除了返回值, 參數(shù), 異常說明外,還必須指出該方法做了什么事情,實(shí)現(xiàn)什么功能. 對(duì)子類的實(shí)現(xiàn)要求以及調(diào)用的注意事項(xiàng)需要一并說明
  • 所有的類都必須添加創(chuàng)建者和創(chuàng)建日期
  • 方法內(nèi)部注釋:
    • 單行注釋: 在被注釋語句上方另起一行,使用 // 注釋
    • 多行注釋: 使用 /* */ 注釋,注意與代碼對(duì)齊
  • 所有枚舉類型字段必須要有注釋,說明每個(gè)數(shù)據(jù)項(xiàng)的用途
  • 當(dāng)水平足夠高時(shí),應(yīng)當(dāng)使用英文注釋. 否則就用中文把問題說清楚,只要將專有名詞關(guān)鍵字保持英文原文即可
  • 代碼修改的同時(shí),注釋也要進(jìn)行相應(yīng)的修改,尤其是參數(shù), 返回值, 異常, 核心邏輯等. 要保持代碼與注釋更新同步
  • 謹(jǐn)慎注釋代碼:
    • 注釋的代碼要進(jìn)行詳細(xì)的說明,而不是簡單的注釋
    • 如果無用,則應(yīng)該刪除
  • 注釋的要求:
    • 能夠準(zhǔn)確反映設(shè)計(jì)思想和代碼邏輯
    • 能夠描述業(yè)務(wù)含義,能夠迅速了解到代碼背后的信息
  • 好的命名,代碼結(jié)構(gòu)是自解釋的,注釋保證精簡準(zhǔn)確,表達(dá)到位
  • 特殊的注釋標(biāo)記,需要注明標(biāo)記人與標(biāo)記時(shí)間.注意及時(shí)處理這些標(biāo)記,通過標(biāo)記掃描,經(jīng)常清理此類標(biāo)記.線上故障有時(shí)候就源于這些標(biāo)記處的代碼
    • 待辦事宜TODO : (標(biāo)記人, 標(biāo)記時(shí)間, [預(yù)處理時(shí)間])?
      • 表示要實(shí)現(xiàn),但目前尚未實(shí)現(xiàn)的功能.這實(shí)際上是一個(gè)Javadoc的標(biāo)簽.只能應(yīng)用于類, 接口, 方法
    • 錯(cuò)誤,不能工作FIXME : (標(biāo)記人, 標(biāo)記時(shí)間, [預(yù)處理時(shí)間])
      • 在注釋中用FIXME標(biāo)記某段代碼是錯(cuò)誤的,而且不能工作,需要及時(shí)糾正情況

前后分離

  • 前后端交互的API,需要明確協(xié)議,域名,路徑,請(qǐng)求方法,請(qǐng)求內(nèi)容,狀態(tài)碼,響應(yīng)體:
    • 協(xié)議: 生產(chǎn)環(huán)境必須使用HTTPS
    • 路徑: 每一個(gè)API需要對(duì)應(yīng)一個(gè)路徑,表示API具體的請(qǐng)求地址
      • 代表資源,只能為名詞,推薦使用復(fù)數(shù),不能為動(dòng)詞,因?yàn)檎?qǐng)求方法已經(jīng)表達(dá)動(dòng)作含義
      • URL路徑不能使用大寫,單詞如果需要分割,統(tǒng)一使用下劃線
      • 路徑禁止攜帶請(qǐng)求內(nèi)容類型的后綴 : ".json",".xml", 通過accept頭表達(dá)即可
    • 請(qǐng)求方法: 對(duì)具體操作的定義
      • GET: 獲取
      • POST: 新增
      • PUT: 修改
      • DELETE: 刪除
    • 請(qǐng)求內(nèi)容:
      • URL帶的參數(shù)必須無敏感信息或者符合安全要求
      • body里帶參數(shù)時(shí)必須設(shè)置Content-Type
    • 響應(yīng)體: 響應(yīng)體body可以放置多種數(shù)據(jù)類型,由Content-Type頭來確定
  • 前后端數(shù)據(jù)列表相關(guān)的接口返回時(shí),如果為空,則返回空數(shù)組 [ ] 或者空集合 { }
  • 服務(wù)端發(fā)生錯(cuò)誤時(shí),返回給前端的響應(yīng)信息必須包含HTTP狀態(tài)碼, errorCode, errorMessage, 用戶提示信息四個(gè)部分:
    • HTTP狀態(tài)碼: 瀏覽器
      • 200 OK : 表明該請(qǐng)求被成功完成, 所請(qǐng)求的資源發(fā)送到客戶端
      • 401 Unauthorized : 請(qǐng)求要求身份驗(yàn)證, 通常是需要登錄而用戶未登錄的情況
      • 403 Forbidden : 服務(wù)器拒絕請(qǐng)求, 通常是機(jī)密信息或復(fù)制其余登錄用戶鏈接訪問服務(wù)器的情況
      • 404 Not Found : 服務(wù)器無法取得所請(qǐng)求的網(wǎng)頁. 請(qǐng)求的資源不存在
      • 500 Internal Server Error: 服務(wù)器內(nèi)部錯(cuò)誤
    • errorCode: 前端開發(fā)
    • errorMessage: 錯(cuò)誤排查人員
    • 用戶提示信息: 用戶. 要求簡短清晰,提示友好,引導(dǎo)用戶進(jìn)行下一步操作或者解釋錯(cuò)誤原因,上下文環(huán)境,推薦操作
  • errorMessage是前后端錯(cuò)誤追蹤機(jī)制的體現(xiàn),可以在前端輸出到 type="hidden" 的文字類控件或者用戶端的日志中,這樣能夠快速地定位問題
  • 對(duì)于需要使用超大整數(shù)的場(chǎng)景,服務(wù)端一律使用String字符串返回類型,禁止使用Long類型
    • Java服務(wù)端如果直接返回Long整型數(shù)據(jù)給前端 ,JS會(huì)自動(dòng)轉(zhuǎn)換為Number類型:
      • Number類型: 雙精度浮點(diǎn)數(shù),表示原理和取值范圍等同于Java中的Double
      • Long類型: 表示的最大值為263 -1. 超過253(9007199254740992) 的數(shù)值轉(zhuǎn)化為JSNumber時(shí),有些數(shù)值會(huì)有精度損失
        • Long取值范圍內(nèi),任何2的指數(shù)次整數(shù)都是絕對(duì)不會(huì)存在精度損失的,所以說精度損失是一個(gè)概率問題
        • 如果浮點(diǎn)數(shù)尾數(shù)位與指數(shù)位空間不限,則可以精確表示任何整數(shù).但是雙精度浮點(diǎn)數(shù)的尾數(shù)位只有52
    • 示例: 通常在訂單號(hào)或者交易號(hào)大于等于16位,大概率會(huì)出現(xiàn)前后端單據(jù)不一致的情況. 比如后端的362909601374617692到前端則是362909601374617660
  • HTTP請(qǐng)求通過URL傳遞參數(shù)時(shí),不能超過2048個(gè)字節(jié):
    • 不同瀏覽器對(duì)于URL的最大長度限制略有不同,并且對(duì)超出最大長度的處理邏輯也有差異. 2048字節(jié)是取所有瀏覽器的最小值
  • HTTP請(qǐng)求通過body傳遞內(nèi)容時(shí),必須控制長度,超出最大長度后,后端解析會(huì)出錯(cuò):
    • Nginx默認(rèn)限制是1MB
    • Tomcat默認(rèn)限制是2MB
    • 當(dāng)確實(shí)有業(yè)務(wù)需要傳較大內(nèi)容時(shí),可以通過調(diào)大服務(wù)器端的限制
  • 在分頁場(chǎng)景中,用戶輸入?yún)?shù)小于1, 則前端返回第一頁參數(shù)給后端. 后端發(fā)現(xiàn)用戶輸入的參數(shù)大于總頁數(shù),直接返回最后一頁
  • 服務(wù)器內(nèi)部重定向必須使用forward. 外部重定向地址必須使用URL統(tǒng)一代理模塊生成,否則會(huì)因?yàn)榫€上采用HTTPS協(xié)議而導(dǎo)致瀏覽器提示 "不安全", 并且還會(huì)帶來URL維護(hù)不一致的問題
  • 服務(wù)器返回信息必須被標(biāo)記是否可以緩存,如果緩存,客戶端可能會(huì)重用之前的請(qǐng)求結(jié)果
    • 緩存有利于減少交互次數(shù),減少交互的平均延遲
    • 示例: http 1.1,s-maxage通知服務(wù)器進(jìn)行緩存,時(shí)間單位為秒:
      • response.setHeader("Cache-Control", "s-maxage=" + cacheSeconds)
  • 服務(wù)端返回的數(shù)據(jù),使用JSON格式而非XML :
    • HTTP支持使用不同的輸出格式,例如純文本,JSON,CSV,XML,RSS以至HTML
    • 在使用面向用戶的服務(wù),應(yīng)該選擇JSON作為通信中使用的標(biāo)準(zhǔn)數(shù)據(jù)交換格式,包括請(qǐng)求和響應(yīng)
      • application/JSON是一種通用的MIME類型,具有實(shí)用,精簡,易讀的特點(diǎn)
  • 前后端的時(shí)間格式統(tǒng)一為 "yyyy-MM-dd HH:mm:ss", 統(tǒng)一為GMT

其它注意

  • 在使用正則表達(dá)式時(shí), 利用好預(yù)編譯功能,可以有效加快正則匹配速度
  • 不要在方法體內(nèi)定義
  • 二方庫中可以定義枚舉類型,參數(shù)可以使用枚舉類型,但是接口返回值不允許使用枚舉類型或者包含枚舉類型的POJO對(duì)象
  • velocity調(diào)用POJO類的屬性時(shí),直接使用屬性名取值即可,模板引擎會(huì)自動(dòng)按規(guī)范調(diào)用POJO的getXxx(), 如果是boolean基本類型變量 ,boolean命名不要加is前綴, 會(huì)自動(dòng)調(diào)用isXxx方法.如果是Boolean包裝類對(duì)象,優(yōu)先調(diào)用getXxx() 方法
  • 后臺(tái)輸送給頁面變量必須加上 $ ! {var},注意中間的感嘆號(hào)
    • 如果var等于null或者不存在,那么${var}會(huì)直接顯示在桌面上
  • 注意Math.random() 這個(gè)方法返回是double類型,取值范圍0 <= x <1(能夠取到零值,注意除零)
    • 如果獲取整數(shù)類型的隨機(jī)數(shù),不需要將x放大10的若干倍然后取整,直接使用Random對(duì)象的nextInt或者nextLong方法
  • 獲取當(dāng)前秒數(shù)System.currentTimeMillis(), 不是使用new Date().getTime()
    • 如果想獲取更加精確的納秒級(jí)時(shí)間值,使用System.nanoTime() 的方式
    • 在JDK 8以后,針對(duì)統(tǒng)計(jì)時(shí)間等常景,需要使用Instant
  • 不要在視圖模版中加入任何復(fù)雜邏輯,根據(jù)MVC理論,視圖的職責(zé)是展示,不要有模型和控制器的代碼邏輯
  • 任何數(shù)據(jù)結(jié)構(gòu)的構(gòu)造和初始化,都應(yīng)指定大小,避免數(shù)據(jù)結(jié)構(gòu)無限增長吃光內(nèi)存
  • 及時(shí)清理不再使用的代碼段或配置信息
    • 對(duì)于垃圾代碼或過時(shí)配置,堅(jiān)決清理干凈,避免程序過度臃腫,代碼冗余
    • 對(duì)于暫時(shí)被注釋掉,后續(xù)可能恢復(fù)使用的代碼片段,在注釋代碼的上方,統(tǒng)一規(guī)定使用三個(gè)斜杠/// 來說明注視掉代碼的理由
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容