Throwable 是全部異常類型的基類,Throwable 下一層分爲兩個分支,Error 和 Exception.java
Error程序員
Error 描述了 JAVA 程序運行時系統的內部錯誤,一般比較嚴重,除了通知用戶和盡力使應用程序安全地終止以外,無能爲力,應用程序不該該嘗試去捕獲這種異常。一般爲一些虛擬機異常,如 StackOverflowError 等。面試
Exception數據庫
Exception 類型下面又分爲兩個分支,一個分支派生自 RuntimeException,這種異常一般爲程序錯誤致使的異常;另外一個分支爲非派生自 RuntimeException 的異常,這種異常一般是程序自己沒有問題,因爲像 I/O 錯誤等問題致使的異常,每一個異常類用逗號隔開。api
受查異常數組
受查異常會在編譯時被檢測。若是一個方法中的代碼會拋出受查異常,則該方法必須包含異常處理,即 try-catch 代碼塊,或在方法簽名中用 throws 關鍵字聲明該方法可能會拋出的受查異常,不然編譯沒法經過。若是一個方法可能拋出多個受查異常類型,就必須在方法的簽名處列出全部的異常類。安全
經過 throws 關鍵字聲明可能拋出的異常函數
private static void readFile(String filePath) throws IOException { File file = new File(filePath); String result; BufferedReader reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } reader.close(); }
try-catch 處理異常組件化
private static void readFile(String filePath) { File file = new File(filePath); String result; BufferedReader reader; try { reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } reader.close(); } catch (IOException e) { e.printStackTrace(); } }
非受查異常性能
非受查異常不會在編譯時被檢測。JAVA 中 Error 和 RuntimeException 類的子類屬於非受查異常,除此以外繼承自 Exception 的類型爲受查異常。
一般,應該捕獲那些知道如何處理的異常,將不知道如何處理的異常繼續傳遞下去。傳遞異常能夠在方法簽名處使用 throws 關鍵字聲明可能會拋出的異常。
private static void readFile(String filePath) throws IOException { File file = new File(filePath); String result; BufferedReader reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } reader.close(); }
有時咱們會從 catch 中拋出一個異常,目的是爲了改變異常的類型。多用於在多系統集成時,當某個子系統故障,異常類型可能有多種,能夠用統一的異常類型向外暴露,不需暴露太多內部異常細節。
private static void readFile(String filePath) throws MyException { try { // code } catch (IOException e) { MyException ex = new MyException("read file failed."); ex.initCause(e); throw ex; } }
在一個 try-catch 語句塊中能夠捕獲多個異常類型,並對不一樣類型的異常作出不一樣的處理
private static void readFile(String filePath) { try { // code } catch (FileNotFoundException e) { // handle FileNotFoundException } catch (IOException e){ // handle IOException } }
同一個 catch 也能夠捕獲多種類型異常,用 | 隔開
private static void readFile(String filePath) { try { // code } catch (FileNotFoundException | UnknownHostException e) { // handle FileNotFoundException or UnknownHostException } catch (IOException e){ // handle IOException } }
習慣上,定義一個異常類應包含兩個構造函數,一個無參構造函數和一個帶有詳細描述信息的構造函數(Throwable 的 toString 方法會打印這些詳細信息,調試時頗有用)
public class MyException extends Exception { public MyException(){ } public MyException(String msg){ super(msg); } // ... }
當方法中發生異常,異常處以後的代碼不會再執行,若是以前獲取了一些本地資源須要釋放,則須要在方法正常結束時和 catch 語句中都調用釋放本地資源的代碼,顯得代碼比較繁瑣,finally 語句能夠解決這個問題。
private static void readFile(String filePath) throws MyException { File file = new File(filePath); String result; BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); while((result = reader.readLine())!=null) { System.out.println(result); } } catch (IOException e) { System.out.println("readFile method catch block."); MyException ex = new MyException("read file failed."); ex.initCause(e); throw ex; } finally { System.out.println("readFile method finally block."); if (null != reader) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
調用該方法時,讀取文件時若發生異常,代碼會進入 catch 代碼塊,以後進入 finally 代碼塊;若讀取文件時未發生異常,則會跳過 catch 代碼塊直接進入 finally 代碼塊。因此不管代碼中是否發生異常,fianlly 中的代碼都會執行。
若 catch 代碼塊中包含 return 語句,finally 中的代碼還會執行嗎?將以上代碼中的 catch 子句修改以下
catch (IOException e) { System.out.println("readFile method catch block."); return; }
調用 readFile 方法,觀察當 catch 子句中調用 return 語句時,finally 子句是否執行
可見,即便 catch 中包含了 return 語句,finally 子句依然會執行。若 finally 中也包含 return 語句,finally 中的 return 會覆蓋前面的 return.
上面例子中,finally 中的 close 方法也可能拋出 IOException, 從而覆蓋了原始異常。JAVA 7 提供了更優雅的方式來實現資源的自動釋放,自動釋放的資源須要是實現了 AutoCloseable 接口的類。
private static void tryWithResourceTest(){ try (Scanner scanner = new Scanner(new FileInputStream("c:/abc"),"UTF-8")){ // code } catch (IOException e){ // handle exception } }
try 代碼塊退出時,會自動調用 scanner.close 方法,和把 scanner.close 方法放在 finally 代碼塊中不一樣的是,若 scanner.close 拋出異常,則會被抑制,拋出的仍然爲原始異常。被抑制的異常會由 addSusppressed 方法添加到原來的異常,若是想要獲取被抑制的異常列表,能夠調用 getSuppressed 方法來獲取。
Error 和 Exception 區別是什麼?
Error 類型的錯誤一般爲虛擬機相關錯誤,如系統崩潰,內存不足,堆棧溢出等,編譯器不會對這類錯誤進行檢測,JAVA 應用程序也不該對這類錯誤進行捕獲,一旦這類錯誤發生,一般應用程序會被終止,僅靠應用程序自己沒法恢復;
Exception 類的錯誤是能夠在應用程序中進行捕獲並處理的,一般遇到這種錯誤,應對其進行處理,使應用程序能夠繼續正常運行。
運行時異常和通常異常區別是什麼?
編譯器不會對運行時異常進行檢測,沒有 try-catch,方法簽名中也沒有 throws 關鍵字聲明,編譯依然能夠經過。若是出現了 RuntimeException, 那必定是程序員的錯誤。
通常一場若是沒有 try-catch,且方法簽名中也沒有用 throws 關鍵字聲明可能拋出的異常,則編譯沒法經過。這類異常一般爲應用環境中的錯誤,即外部錯誤,非應用程序自己錯誤,如文件找不到等。
NoClassDefFoundError 和 ClassNotFoundException 區別是什麼?
NoClassDefFoundError 是一個 Error 類型的異常,是由 JVM 引發的,不該該嘗試捕獲這個異常。引發該異常的緣由是 JVM 或 ClassLoader 嘗試加載某類時在內存中找不到該類的定義,該動做發生在運行期間,即編譯時該類存在,可是在運行時卻找不到了,多是變異後被刪除了等緣由致使;
ClassNotFoundException 是一個受查異常,須要顯式地使用 try-catch 對其進行捕獲和處理,或在方法簽名中用 throws 關鍵字進行聲明。當使用 Class.forName, ClassLoader.loadClass 或 ClassLoader.findSystemClass 動態加載類到內存的時候,經過傳入的類路徑參數沒有找到該類,就會拋出該異常;另外一種拋出該異常的可能緣由是某個類已經由一個類加載器加載至內存中,另外一個加載器又嘗試去加載它。
JVM 是如何處理異常的?
在一個方法中若是發生異常,這個方法會建立一個一場對象,並轉交給 JVM,該異常對象包含異常名稱,異常描述以及異常發生時應用程序的狀態。建立異常對象並轉交給 JVM 的過程稱爲拋出異常。可能有一系列的方法調用,最終才進入拋出異常的方法,這一系列方法調用的有序列表叫作調用棧。
JVM 會順着調用棧去查找看是否有能夠處理異常的代碼,若是有,則調用異常處理代碼。當 JVM 發現能夠處理異常的代碼時,會把發生的異常傳遞給它。若是 JVM 沒有找到能夠處理該異常的代碼塊,JVM 就會將該異常轉交給默認的異常處理器(默認處理器爲 JVM 的一部分),默認異常處理器打印出異常信息並終止應用程序。
throw 和 throws 的區別是什麼?
throw 關鍵字用來拋出方法或代碼塊中的異常,受查異常和非受查異常均可以被拋出。
throws 關鍵字用在方法簽名處,用來標識該方法可能拋出的異常列表。一個方法用 throws 標識了可能拋出的異常列表,調用該方法的方法中必須包含可處理異常的代碼,不然也要在方法簽名中用 throws 關鍵字聲明相應的異常。
常見的 RuntimeException 有哪些?
原文:https://www.imooc.com/article/275564#