JAVA編程規範之異常日誌

(異常處理

1. 【強制】不要捕獲Java類庫中定義的繼承自RuntimeException的運行時異常類,如:IndexOutOfBoundsException / NullPointerException,這類異常由程序員預檢查來規避,保證程序健壯性。

正例:if(obj!= null) {...}

反例:try { obj.method() } catch(NullPointerException e){…}

2. 【強制】異常不要用來做流程控制,條件控制,因爲異常的處理效率比條件分支低。

3. 【強制】對大段代碼進行try-catch,這是不負責任的表現。catch時請分清穩定代碼和非穩定代碼,穩定代碼指的是無論如何不會出錯的代碼。對於非穩定代碼的catch儘可能進行區分異常類型,再做對應的異常處理。

4. 【強制】捕獲異常是爲了處理它,不要捕獲了卻什麼都不處理而拋棄之,如果不想處理它,請將該異常拋給它的調用者。最外層的業務使用者,必須處理異常,將其轉化爲用戶可以理解的內容。

5. 【強制】有try塊放到了事務代碼中,catch異常後,如果需要回滾事務,一定要注意手動回滾事務。

6. 【強制】finally塊必須對資源對象、流對象進行關閉,有異常也要做try-catch

說明:如果JDK7,可以使用try-with-resources方法。

7. 【強制】不能在finally塊中使用returnfinally塊中的return返回後方法結束執行,不會再執行try塊中的return語句。

8. 【強制】捕獲異常與拋異常,必須是完全匹配,或者捕獲異常是拋異常的父類。

說明:如果預期拋的是繡球,實際接到的是鉛球,就會產生意外情況。

9. 【推薦】方法的返回值可以爲null,不強制返回空集合,或者空對象等,必須添加註釋充分說明什麼情況下會返回null值。調用方需要進行null判斷防止NPE問題。

說明:本規約明確防止NPE是調用者的責任。即使被調用方法返回空集合或者空對象,對調用者來說,也並非高枕無憂,必須考慮到遠程調用失敗,運行時異常等場景返回null的情況。

10.【推薦】防止NPE,是程序員的基本修養,注意NPE產生的場景:

1 返回類型爲包裝數據類型,有可能是null,返回int值時注意判空。

反例:public int f(){ returnInteger對象},如果爲null,自動解箱拋NPE

2 數據庫的查詢結果可能爲null

3 集合裏的元素即使isNotEmpty,取出的數據元素也可能爲null

4 遠程調用返回對象,一律要求進行NPE判斷。

5 對於Session中獲取的數據,建議NPE檢查,避免空指針。

6 級聯調用obj.getA().getB().getC();一連串調用,易產生NPE

11.【推薦】在代碼中使用拋異常還是返回錯誤碼,對於公司外的http/api開放接口必須使用錯誤碼;而應用內部推薦異常拋出;跨應用間RPC調用優先考慮使用Result方式封裝isSuccess錯誤碼錯誤簡短信息

說明:關於RPC方法返回方式使用Result方式的理由:

1)使用拋異常返回方式,調用方如果沒有捕獲到就會產生運行時錯誤。

2)如果不加棧信息,只是new自定義異常,加入自己的理解的error message,對於調用端解決問題的幫助不會太多。如果加了棧信息,在頻繁調用出錯的情況下,數據序列化和傳輸的性能損耗也是問題。

12.【推薦】定義時區分unchecked / checked 異常,避免直接使用RuntimeException拋出,更不允許拋出Exception或者Throwable,應使用有業務含義的自定義異常。推薦業界已定義過的自定義異常,如:DaoException / ServiceException等。

13.【參考】避免出現重複的代碼(Don’t RepeatYourself),即DRY原則。

說明:隨意複製和粘貼代碼,必然會導致代碼的重複,在以後需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是共用模塊。

正例:一個類中有多個public方法,都需要進行數行相同的參數校驗操作,這個時候請抽取:

private boolean checkParam(DTO dto){...}

(日誌規約

1. 【強制】應用中不可直接使用日誌系統(Log4jLogback)中的API,而應依賴使用日誌框架

SLF4J中的API,使用門面模式的日誌框架,有利於維護和各個類的日誌處理方式統一。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

private static final Logger logger = LoggerFactory.getLogger(Abc.class);

2. 【強制】日誌文件推薦至少保存15天,因爲有些異常具備以爲頻次發生的特點。

3. 【強制】應用中的擴展日誌(如打點、臨時監控、訪問日誌等)命名方式:appName_logType_logName.loglogType:日誌類型,推薦分類有stats/desc/monitor/visit

等;logName:日誌描述。這種命名的好處:通過文件名就可知道日誌文件屬於什麼應用,什麼

類型,什麼目的,也有利於歸類查找。

正例:mppserver應用中單獨監控時區轉換異常,如:

mppserver_monitor_timeZoneConvert.log

說明:推薦對日誌進行分類,錯誤日誌和業務日誌儘量分開存放,便於開發人員查看,也便於通過日誌對系統進行及時監控。

4. 【強制】對 trace/debug/info級別的日誌輸出,必須使用條件輸出形式或者使用佔位符的方式。

說明:logger.debug("Processing trade with id: " + id + " symbol: " + symbol); 如果日誌級別是 warn,上述日誌不會打印,但是會執行字符串拼接操作,如果 symbol是對象,會執行 toString()方法,浪費了系統資源,執行了上述操作,最終日誌卻沒有打印。

正例:(條件)

if (logger.isDebugEnabled()) {

logger.debug("Processing trade with id: " +id + " symbol: " + symbol);

}

正例:(佔位符)

logger.debug("Processing trade with id:{} and symbol : {} ", id, symbol);

5. 【強制】避免重複打印日誌,浪費磁盤空間,務必在 log4j.xml中設置 additivity=false

正例:<logger name="com.taobao.ecrm.member.config" additivity="false">

6. 【強制】異常信息應該包括兩類信息:案發現場信息和異常堆棧信息。如果不處理,那麼往上拋。

正例:logger.error(各類參數或者對象 toString + "_" + e.getMessage(), e);

7. 輸出的 POJO類必須重寫 toString方法,否則只輸出此對象的 hashCode值(地址值),沒啥參考意義。

8. 【推薦】可以使用 warn日誌級別來記錄用戶輸入參數錯誤的情況,避免用戶投訴時,無所適從。注意日誌輸出的級別,error級別只記錄系統邏輯出錯、異常、或者重要的錯誤信息。如非必要,請不要在此場景打出 error級別,避免頻繁報警。

9. 【推薦】謹慎地記錄日誌。生產環境禁止輸出 debug日誌;有選擇地輸出 info日誌;如果使 warn來記錄剛上線時的業務行爲信息,一定要注意日誌輸出量的問題,避免把服務器磁盤撐爆,並記得及時刪除這些觀察日誌。

說明:大量地輸出無效日誌,不利於系統性能提升,也不利於快速定位錯誤點。紀錄日誌時請

思考:這些日誌真的有人看嗎?看到這條日誌你能做什麼?能不能給問題排查帶來好處?

10.【參考】如果日誌用英文描述不清楚,推薦使用中文註釋。對於中文 UTF-8的日誌,在 secureCRT中,setencoding=utf-8;如果中文字符還亂碼,請設置:全局>默認的會話設置>外觀>字體>選擇字符集 gb2312;如果還不行,執行命令:set termencoding=gbk,並且直接使用中文來進行檢索。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章