1、java異常體系java
先看Java異常體系圖:app
全部異常類的父類爲Throwable類,兩個直接子類爲Error和Exception分別表示錯誤和異常。ui
一、Error類this
Error是程序沒法處理的錯誤,它是由JVM產生和拋出的,好比OutOfMemoryError、ThreadDeath等。這些異常發生時,Java虛擬機(JVM)通常會選擇線程終止。編碼
二、Exception類spa
Exception是程序自己能夠處理的異常,這種異常分兩大類運行時異常(Unchecked Exception)和非運行時異常(Checked Exception)。程序中應當儘量去處理這些異常。線程
RuntimeException(Unchecked Exception):便可以編譯經過,通常由程序的邏輯錯誤引發,開發過程當中應儘可能避免。例如:NullPointerException,IndexOutOfBoundsException等。自定義異常通常繼承此類。
3d
RuntimeException之外的異常(checked Exception):編譯器在編譯階段進行處理,程序必須處理此類異常不然沒法經過編譯,如IOException、SQLException等。日誌
2、異常的捕獲和處理code
異常的捕獲經過try、catch、finally三個關鍵字,三個語句塊均不能單獨使用,三者能夠組成 try...catch...finally、try...catch、try...finally三種結構,catch語句能夠有一個或多個,finally語句只能一個
一、普通無異常:
public class TestDemo { public static void main(String[] args) { String result = GetString(); System.out.print(result); } public static String GetString(){ try { System.out.print("GetString():try\n"); return "GetString()返回值\n"; } catch (Exception e) { System.out.print("GetString():catch\n"); return "GetString()返回值"; } finally { System.out.print("GetString():finally\n"); } //return "這裏是方法底部返回值"; } }
運行結果:
整個執行順序以下:執行順序是try=>finally=>return
二、出現異常調用狀況
public class TestDemo { public static void main(String[] args) { String result = GetString(); System.out.print(result); } public static String GetString(){ try { System.out.print("GetString():try\n"); int i = 0; int var = 1 / i ; System.out.print("執行GetString():1/i\n"); return "GetString()try 返回值\n"; } catch (Exception e) { System.out.print("GetString():catch\n"); return "GetString()catch 返回值"; } finally { System.out.print("GetString():finally\n"); } //return "這裏是方法底部返回值"; } }
執行結果:
整個執行順序以下:try=>catch=>finally=>catch return
能夠肯定:
1)不論出不出現異常都會執行finally代碼塊
2)在try模塊中出現異常後,異常代碼後續流程都不會繼續執行
三、try、catch、finally模塊中進行賦值
public class TestDemo { public static void main(String[] args) { String result = GetString(); System.out.print(result); } public static String GetString(){ String var = ""; try { var = "try var值"; System.out.print("執行GetString():var\n"); return var; } catch (Exception e) { System.out.print("GetString():catch\n"); return "GetString()catch 返回值"; } finally { var = "finally var值"; System.out.print("GetString():finally\n"); } } }
執行結果:
經過執行結果能夠看到,在finally中對var進行賦值,雖然程序執行了finally模塊,可是最終不會影響var的值,var的值仍是在try模塊中賦值內容。
結論:雖然finally方法會被執行可是返回結果不會被改變,也就是finally是在return以後執行的,try模塊會先把返回結果先保存起來,而後無論finally代碼執行了什麼,都不會影響到返回結果,等finally執行完成在返回結果。
3、業務如何定義異常
業務中須要按照必定的規範來定義異常,這樣有利於系統管理業務異常。
經過上面繼承圖能夠看出,全部service都會繼承BaseExcepion,BaseException最終經過RuntimeException來實現。
而在實際的業務中須要準肯定位異常歸屬的服務和具體類型,這樣就能夠在對異常日誌進行監控時有區分的進行不一樣的處理(好比重要的賬務或者渠道服務進行較高優先級的提醒或者自處理)。
因此能夠在BaseException經過系統定義的code,code經過兩個部分來組成:不一樣的service定義的值和同一個service中具體異常類型值。
public class BaseException extends RuntimeException { private String code; public BusinessException() { super(); } public BusinessException(String code, String message) { super(message); this.code = code; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } /** * 獲取異常編碼 * @param sysCode 系統編號枚舉 * @param exceptionType 異常類型枚舉 * @param exceptionCode 異常順序碼 * @return String 異常編碼 */ protected static String getExceptionCode(SysCode sysCode, ExceptionType exceptionType, String exceptionCode) { if (StringUtil.isEmpty(exceptionCode) || StringUtil.length(exceptionCode) != 4) { throw new BusinessException("00000000", "異常編碼不符規範"); } return new StringBuilder(sysCode.getCode()).append(exceptionType.getCode()).append(exceptionCode).toString(); } public BusinessException print(String message) { logger.error("BusinessException Code:{};Message:{};OtherMessage:{}", this.code, super.getMessage(), message); return this; }
在serviceA中經過調用定義異常類型ORDER_PARAM_NULL,自己ServiceA自帶code:SysCode.SER_A,再和定義的1001進行拼接獲得最終的該異常在整個系統中的異常code。
public class ServiceAException extends BusinessException { public static FeeException ORDER_PARAM_NULL = new ServiceAException(getExceptionCode( "1001"), "關鍵參數爲空"); public static String getExceptionCode(String exceptionCode) { return getExceptionCode(SysCode.SER_A/*這裏定義serviceA的系統code值*/, exceptionCode); } }