摘要:java異常指在程序運行時可能出現的一些錯誤,如:文件找不到、網絡連接失敗、非法參數等。異常是一個事件,它發生在程序運行期間,中斷了正在執行的程序的正常指令流。
本文分享自華為雲社區《Java知識點問題精選之異常機制》,原文作者:breakDraw 。
java異常指在程序運行時可能出現的一些錯誤,如:文件找不到、網絡連接失敗、非法參數等。異常是一個事件,它發生在程序運行期間,中斷了正在執行的程序的正常指令流。
Java通過API中Throwable類的眾多子類描述各種不同的異常。因而,Java異常都是對象,是Throwable子類的實例,描述了出現在一段編碼中的錯誤條件。當條件生成時,錯誤將引發異常。對於運行時異常、錯誤或可查異常,Java技術所要求的異常處理方式有所不同。
異常體系分類
Q: Throwable 和 Error的關系
A: Throwable是Error(錯誤)的基類,也是Exception的基類
1個好圖,可看到常見的異常和error
Q: Error和Exception的關系
A:
- Error一般是會直接引起jvm出錯的錯誤,例如Java虛擬機運行錯誤等,如果出現了當前線程會無法繼續運行。
- Excpetion是程序本身可以處理的異常。發生后還能正常運行。
Q: Error可以被catch捕捉嗎?
A: 只要是Throwable和其子類都是可以throw和catch的。 但是不建議捕捉Error。
異常體系還可以分為這2類:
- unchecked exception(非檢查異常)
也稱運行時異常(RuntimeException),比如常見的NullPointerException、IndexOutOfBoundsException。對於運行時異常,java編譯器不要求必須進行異常捕獲處理或者拋出聲明,由程序員自行決定。 - checked exception(檢查異常,編譯異常)
也稱非運行時異常(運行時異常以外的異常就是非運行時異常),java編譯器強制程序員必須進行捕獲處理,比如常見的IOExeption和SQLException。對於非運行時異常如果不進行捕獲或者拋出聲明處理,編譯都不會通過。
異常捕捉和返回
Q: return-finally陷阱1: finally能通過修改變量,來更新return的變量值嗎
int f() { int a = 1; try { return a; } finally { a=2; } }
A: 不能, f返回1。
Q: return-finally陷阱2: finally里也return時,返回哪個?
int f() { try { return 1; } finally { return 2; } }
A:返回finally里的,返回2。
Q: 什么情況下finally塊里的步驟可以不執行?
A: 只有在finally之前調用System.exit(0)退出jvm, 才能讓finally不執行。
Q: 下面會發生什么?
try { start(); } catch (Exception ex) { System.out.println("catch Exception"); } catch (RuntimeException re) { System.out.println("catch RuntimeException"); }
A: 直接編譯就錯誤了。 catch是會按順序的且匹配1個就不再往下匹配,編譯器因此識別出RuntimeExcpetion永遠不會被捕捉到,便提前報錯。
Q:throw異常的時候,在finally中做return,那么異常還會拋出嗎?
static int f() { try { int a = 1/0; return a; } catch (Exception e) { throw new RuntimeException(e); } finally { return -1; } } public static void main(String[] args) { System.out.println(f()); }
A:不會,返回-1.
即finaly中做return會中斷throw
因此永遠不要在finally中去做return操作
受檢異常相關問題
Q: 子類覆寫基類方法時 , 能throws基類方法中不存在的異常嗎?
像下面這樣:
class A{ void f() throws IOException{ } } class B extends A{ void f() throws IOException, SQLException { } }
A: 不行,直接編譯報錯。 即子類覆寫父類方法時, throws關鍵字后面跟的異常必須是小於等於父類方法異常的。
Q: finally中調用某資源的close時,也會拋出受檢異常, 除了在finally里做try-catch,還能怎么做?
像下面這樣,finally又有catch,就很難看:
TryWithResource tryWithResource = new TryWithResource(); try { System.out.println(tryWithResource.age); } catch (Exception e) { e.printStackTrace(); }finally { try { tryWithResource.close(); } catch (Exception e) { e.printStackTrace(); } }
A:如果是JDK1.7,可以用try-with-resource語法。
需要資源類實現AutoCloseable接口, 並在try的時候在try括號后面跟上資源的創建,如下:
public static void main(String[] args) { try (TryWithResource tryWithResource = new TryWithResource()) { System.out.println(tryWithResource.age); } catch (Exception e) { e.printStackTrace(); } }
這樣就不需要寫finally,finally+close會通過編譯器給我們自動加上。
Q: 線程拋出異常的話該怎么捕捉?
A: 實現異常處理接口MyUnchecckedExceptionhandler
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("捕獲異常處理方法:" + e); } }
然后把實現類設置給對應線程。
Thread t = new Thread(new ExceptionThread()); t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler()); t.start();