程序員、Java後端、面試題、異常類型、日誌
吐槽
最近看公司業務代碼發現異常那塊天天用,但理解不深啊
趕緊複習下,我還是有一顆學習的心
互聯網項目一個異常、一個日誌都非常重要,設計的不好後果很痛苦。
異常類型
Throwable有兩個子類,Error和Exception
Checked Exception
Unchecked Exception
基本概念掃盲
- 異常和錯誤的區別是,異常是可以被處理的,而錯誤是沒法處理的。
- Error也是unchecked exception,也是無法預先處理的。
- 所有checked exception都是需要在代碼中處理的,它們的發生是可以預測的
check異常
如Exception /IOException
uncheck異常
RuntimeException及他的子類
check異常總結
- 編譯保證,沒catch或throws編譯報錯
- throw的是check異常就當前方法必須 throws Exception 或catch 住
- throw的是check異常throws Exception這個異常了,上層方法必須 catch
uncheck異常總結
- 公司的自定義異常類都是基礎RuntimeException,然後配合異常枚舉
- com.google.common.base.Preconditions#checkArgument(boolean, java.lang.Object) 公司大佬喜歡用這個異常工具,自己可以參考造一個出來
異常理解
編譯錯誤案例代碼
public static void throwChecked(int a) { if (a > 0) { //自行拋出Exception異常 //該代碼必須處於try塊裡,或處於帶throws聲明的方法中 throw new Exception("a的值大於0,不符合要求"); } }
idea 會提示 :Unhandled exception: java.lang.Exception
正常異常案例代碼
public static void throwChecked(int a)throws Exception { if (a > 0) { //自行拋出Exception異常 //該代碼必須處於try塊裡,或處於帶throws聲明的方法中 throw new Exception("a的值大於0,不符合要求"); } }
企業自定義異常類
優秀IT企業裡不是創建一堆自定義異常,而是異常類配合異常枚舉來設計
一般業務系統自定義異常類不要少過3個
get/set方法我就省略了
public class WangException extends RuntimeException { /**錯誤碼*/ private WangErrorCodeEnum errorCode; /**詳細錯誤信息*/ private Map errorMap = new HashMap(); /** * 帶參構造器. * @param errorCode */ public WangException(WangErrorCodeEnum errorCode) { super(errorCode.getDesc()); this.setErrorCode(errorCode); } /** * 帶參構造器 */ public WangException(WangErrorCodeEnum errorCode, String message) { super(StringUtils.isNotBlank(message) ? message : errorCode.getDesc()); this.setErrorCode(errorCode); } /** * 帶參構造器. * @param errorCode * @param errorContext */ public WangException(WangErrorCodeEnum errorCode, ErrorContext errorContext) { this(errorCode, findMessage(errorContext)); } /** * 帶參構造器. * @param errorCode * @param errorMap */ public WangException(WangErrorCodeEnum errorCode, Map errorMap) { this(errorCode); this.errorMap = errorMap; } /** * 帶參構造器. * @param errorCode * @param message */ public WangException(WangErrorCodeEnum errorCode, String message, Map errorMap) { super(StringUtils.isNotBlank(message) ? message : errorCode.getDesc()); this.setErrorCode(errorCode); this.errorMap = errorMap; } /** * 帶參構造器. * * @param message */ public WangException(String message) { super(message); this.setErrorCode(WangErrorCodeEnum.UNKNOWN_SYS_ERROR); }
錯誤枚舉
public enum WangErrorCodeEnum { SYS_ERROR("SYS_ERROR", "系統錯誤,請重試"), UNKNOWN_SYS_ERROR("UNKNOWN_SYS_ERROR", "未知的系統異常"),
高級點的異常枚舉
有日誌級別、是系統還是業務異常、日誌是error還是warn、info等等
SYSTEM_ERROR("000", ErrorLevels.ERROR, ErrorTypes.SYSTEM, "系統異常"),
模板模式
異常從dao、service等等拋上來後,
需要把異常信息轉換封裝返回給前端、或rpc調用端等等
這裡一般可以採用模板模式,把各種異常的catch 轉換封裝
業務代碼裡只要調用模板代碼即可,什麼異常轉換、日誌記錄都統一管理,
業務代碼乾淨多了,技術經理看到又可以加工資了
日誌規範
生產上儘量把info、error、warn分清楚
切記不要都打到error裡面了(很多公司對error非常敏感的)
異常日誌打印儘量把 場景、異常具體原因、影響業務等等打清楚,
異常碼異常描述儘量精細,
大型分佈式項目中日誌好不好
決定了下班早不早,
平時寫業務代碼習慣打印“其他異常”,生產出故障了就發現自己是多麼的坑爹
分佈式trace_id非常強大,後邊我研究下整理整理