目錄
零、引言
一、基礎
二、集合
三、并發
四、日志
五、安全
零、引言
規范等級:
|
一、基礎
序號 | 等級 | 規范 | 示例?? | 說明 | |||
---|---|---|---|---|---|---|---|
1 | 強制 | 在POJO類中定義布爾類型成員變量時,禁止用is作變量名前綴。 | 反例:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
| is作變量名前綴的布爾型成員變量,在一些IDE(如:IDEA)中,默認生成的getter方法與變量名相同,導致部分框架(如:Jackson、Fastjson)在反向解析時會引發“找不到指定成員變量名”的錯誤。 | |||
2 | 強制 | 在對象之間做相等比較時,應當使用Objects工具類(java.util.Objects)的equals方法。 | 正例:
反例:
| 當對象為null時,直接調用equals會出現空指針異常。 注意:Objects的equals方法內部會利用參數對象的equals方法進行比較,對數組、集合之類的對象并不會做內部元素的一一比較。 | |||
3 | 強制 | 在BigDecimal之間做等值比較時,禁止使用equals方法。 | 正例:
反例:
| BigDecimal的equals方法會比較精度,如1.0與1.00比較的結果為false,推薦使用其 compareTo方法做比較。 | |||
4 | 強制 | 在浮點數之間做等值比較時,基本類型禁止使用==,包裝類型禁止使用equals。 | 正例:
反例:
反例:
| 浮點數先轉成BigDecimal,再用compareTo方法做比較,以避免精度問題影響結果。 浮點數采用“尾數+階碼”的編碼方式,類似于科學計數法的“有效數字+指數”的表示方式。二進制無法精確表示大部分的十進制小數。 | |||
5 | 強制 | 將浮點數轉換為BigDecimal 時,禁止直接使用構造方法。 | 正例:
反例:
| BigDecimal的浮點數構造方法存在精度損失風險,在精確計算或值比較的場景中會導致業務邏輯異常。 注意:和上一條的正例不同的是,前者在經過浮點計算后已經形成了誤差,在轉換時用toScaledBigDecimal方法限定了精度。在此處,是為了避免因直接利用浮點數構造而導致的誤差。 | |||
6 | 強制 | 在空指針異常易發的場景中,應當對對象做null判斷。 | 正例:
反例:
| 在對象未判斷null的情況下直接引用,容易發生空指針異常,推薦用Optional類更優雅的處理null對象。 一些空指針異常(NPE)易發的場景:
| |||
7 | 強制 | 在日期格式化時,應當使用DateUtils工具類 | 正例
反例
| DateUtils包裝了常用的日期格式,避免了手動格式化時的誤用風險,如:年份格式化誤書寫成YYYY,如本周存在跨年的情況,返回的就是下一年。 | |||
8 | 強制 | POJO類屬性,禁止使用基本數據類型。 | 正例
反例:
| POJO類屬性使用包裝數據類型有如下優點:
|
二、集合
序號 | 等級 | 規范 | 示例 | 說明 | ||
---|---|---|---|---|---|---|
1 | 強制 | 在需要對List的subList方法返回結果進行遍歷、增加、刪除元素時,禁止直接變更原List中的元素。 | 反例:
| List的subList方法返回的是一個List的內部類對象,它是List的一個視圖,對原List所有的操作都會反映到這個對象上。 同時,對原List進行元素的增加或刪除,會被計數(modCount,結構變更次數),此數值和原subList時記錄的數值(expectedModCount)不一致,會引發ConcurrentModification Exception異常。 | ||
2 | 強制 | 對集合進行for循環時,禁止在循環體內用remove/add方法。 | 正例:
反例:
| 若在for循環體內對集合元素進行remove/add操作,可能導致異常,建議使用iterator方式處理。 |
三、并發
序號 | 等級 | 規范 | 示例 | 說明 | ||
---|---|---|---|---|---|---|
1 | 強制 | 動態線程池只允許使用通義管理平臺定義的(比如Poseidon),禁止自行創建。 | 正例:
反例:
| 通過Poseidon創建的線程池將能較好的進行管理和監控:
| ||
2 | 強制 | 在使用線程池時,禁止將拒絕策略設置為DiscardPolicy。 | 反例:
| 若配置了DiscardPolicy,當線程池隊列排滿且已達到了最大線程數后,新增任務會被直接丟棄,無任何提示,并且在結合future.get()運行時,存在阻塞的風險。 | ||
3 | 強制 | 父子任務禁止使用同一個線程池。 | 反例:
| 父子任務使用同一個線程池容易相互影響,線程數達上限時,子任務等待線程資源,而同時,父任務因子任務未完成,其資源得不到釋放,最終可能導致相互等待或死鎖。 | ||
4 | 強制 | 在多線程環境下,禁止直接使用HashMap。 | 正例:
反例:
| HashMap是線程不安全的,在容量不夠進行resize時,可能因并發出現死鏈,導致CPU飆升。 |
四、日志
序號 | 等級 | 規范 | 示例 | 說明 | ||
---|---|---|---|---|---|---|
1 | 強制 | 日志級別只允許使用ERROR、WARN、INFO、DEBUG。 | 正例:
|
| ||
2 | 強制 | 業務受損或預期外的異常場景,應當打印ERROR日志。 | 正例:
反例:
| ERROR日志用于描述異常不可控的場景,當該類異常發生的時候會給業務和系統帶來傷害,需要第一時間告警并介入排查修復。 | ||
3 | 強制 | 業務不受損且預期內的異常場景,應當打印WARN日志。 | 正例:
| WARN日志用于描述異常可控的場景,當該類異常發生的時候不會給業務和系統帶來傷害,用于記錄和觀測,指導進一步處理。 | ||
4 | 推薦 | 打印日志時,建議使用占位符的方式拼裝內容。 | 正例:
反例:
| ”+“ 拼接會多次調用StringBuilder的append()方式,每一次append的時候會計算字符串的長度以及重新分配一次內存,對性能有一定的損耗。 此外,“+”拼接方式無論本條日志是否打印都會計算長度和分配內存,而占位符的方式僅在打印的時候才進行內存分配。 | ||
5 | 推薦 | 打印日志時,不建議使用JSON工具將對象轉換成String。 | 正例
反例:
| 如果對象里某些get方法被覆寫,存在拋出異常的風險,進而影響正常業務流程。 | ||
6 | 推薦 | 異常日志內容中應當包含三要素:異常場景、異常數據、異常堆棧。 | 正例:
反例:
| 異常日志內容應記錄關鍵的信息(異常場景、異常數據、異常堆棧),為問題排查提供有效幫助,能更高效的處理線上故障。 三要素包含: 異常場景:出現異常的業務場景說明。 異常數據:出現異常的數據(比如下單場景,需要記錄商品ID、用戶ID等信息)。 異常堆棧:異常堆棧信息。 |
五、安全
序號 | 等級 | 規范 | 示例 | 說明 | ||
---|---|---|---|---|---|---|
1 | 強制 | 用戶敏感數據禁止直接展示、禁止用Get方式提交。 | 反例:
| 手機號、銀行卡卡號、身份證、車牌、車架號等都屬于用戶敏感信息,不能直接展示。 脫敏方式:
禁止用Get方式提交,這種方式在URL上帶有敏感數據,將會在wan/lan日志中出現這些元數據。 | ||
2 | 強制 | 用戶輸入的參數,禁止直接拼接到SQL訪問數據庫。 | 反例:
| 用戶輸入的參數可能帶有SQL片段,存在SQL注入的風險,需要使用參數綁定的技術來防范。 | ||
3 | 強制 | 未經許可,禁止外發公司任何程序代碼。 | 反例:
| 程序代碼屬于公司資產,在未經許可的情況下不得以任何方式(郵件、IM軟件、紙質打印等)向外傳輸或公開,包括但不僅限于:
|