一、前言
Java中異常分為兩種:一種是基于Error的,一種是基于Exception的。其兩者都是繼承自Throwable;其中Error錯誤一般都是不可恢複的錯誤,比如系統崩潰、虛拟機錯誤,記憶體空間不足、類定義找不到、方法調用棧溢出等;而Exception錯誤則是我們經常使用來做業務異常攔截的;對于Error類型錯誤一般由于是不可恢複錯誤,是以沒必要catch掉,但是凡事都有例外...
二、來龍去脈
如下代碼,service()方法用來模拟業務服務,代碼比較簡單,一般下我們是首先建立一個傳回對象,然後在try塊中執行業務,然後設定結果;執行異常後在catch使用Exception類型捕獲異常,然後設定result傳回值為false。最後傳回結果,這個代碼看起來很正常:
public class Test {
// 業務伺服器提供的服務
public static Result service() {
// 1.建立傳回對象
Result result = new Result();
result.setSucess(true);
// 2.執行業務
try {
// 2.1執行業務,設定傳回值 .....
...
result.setData("ok");
} catch (Exception e) {
// 2.2比如業務異常則設定為false,并且傳回異常資訊
result.setSucess(false);
result.setCode("biz-error1");
}
// 3.傳回結果
return result;
}
public static void main(String[] args) throws InterruptedException, ClassNotFoundException {
Executor executor = Executors.newFixedThreadPool(5);
executor.execute(() -> {
System.out.println(JSON.toJSONString(service()));
});
executor.shutdown();
}
}
複制
當service()服務線上程池裡面執行時候,并且service()方法裡面抛出NoClassDefFoundError異常後,我們會看不到System.out.println(JSON.toJSONString(service()));輸出結果,也不知道異常NoClassDefFoundError跑到哪裡去了,這非常不利于排查問題。
由于NoClassDefFoundError是繼承自Error,而Error繼承自Throwable,是以我們有必要在加一個catch塊來捕獲Throwable異常:
public static Result service() {
// 1.建立傳回對象
Result result = new Result();
result.setSucess(true);
// 2.執行業務
try {
// 2.1執行業務,設定傳回值 .....
if (true) {
throw new NoClassDefFoundError("calss def can not found");
}
result.setData("ok");
} catch (Exception e) {
// 2.2比如業務異常則設定為false,并且傳回異常資訊
result.setSucess(false);
result.setCode("biz-error1");
} catch (Throwable e) {
// 2.3比如不可恢複的異常,比如NoClassDefFoundError,則設定為false,并且傳回異常資訊
result.setSucess(false);
result.setCode("sys-error1");
System.out.println(e.getLocalizedMessage());
}
// 3.傳回結果
return result;
}
複制
當然要想實作簡單捕獲線程中抛出的異常也可以實作UncaughtExceptionHandler來捕獲。
三、總結
雖然Error類型的錯誤是不可恢複錯誤,但是有時候我們還是需要顯示的捕獲并列印日志,以便問題排查;另外比如NoClassDefFoundError類型錯誤,可以隻是應用中部分服務不可用,但是其他子產品服務是可用的,是以這時候我們還是要理會的。