Throwable這個類是Java中用老表示任何能夠做爲異常被拋出的基類,於是Java異常都是對象,是Throwable子類的實例,描述了出如今一段編碼中的 錯誤條件。當條件生成時,錯誤將引起異常。html
Java異常類層次結構圖:java
圖片來自:http://www.benchresources.net/exception-hierarchy-in-java/程序員
在 Java 中,全部的異常都有一個共同的祖先 Throwable(可拋出)。Throwable 指定代碼中可用異常傳播機制經過 Java 應用程序傳輸的任何問題的共性。
Throwable: 有兩個重要的子類:Exception(異常)和 Error(錯誤),兩者都是 Java 異常處理的重要子類,各自都包含大量子類。數據庫
Error(錯誤):是程序沒法處理的錯誤,表示運行應用程序中較嚴重問題。大多數錯誤與代碼編寫者執行的操做無關,而表示代碼運行時 JVM(Java 虛擬機)出現的問題。例如,Java虛擬機運行錯誤(Virtual MachineError),當 JVM 再也不有繼續執行操做所需的內存資源時,將出現 OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)通常會選擇線程終止。這些錯誤表示故障發生於虛擬機自身、或者發生在虛擬機試圖執行應用時,如Java虛擬機運行錯誤(Virtual MachineError)、類定義錯誤(NoClassDefFoundError)等。這些錯誤是不可查的,由於它們在應用程序的控制和處理能力之 外,並且絕大多數是程序運行時不容許出現的情況。對於設計合理的應用程序來講,即便確實發生了錯誤,本質上也不該該試圖去處理它所引發的異常情況。在 Java中,錯誤經過Error的子類描述。數組
Exception(異常):是程序自己能夠處理的異常。安全
Exception 類有一個重要的子類 RuntimeException。RuntimeException 類及其子類表示「JVM 經常使用操做」引起的錯誤。例如,若試圖使用空值對象引用、除數爲零或數組越界,則分別引起運行時異常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。ui
注意:異常和錯誤的區別:異常能被程序自己能夠處理,錯誤是沒法處理。編碼
一般,Java的異常(包括Exception和Error)分爲可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。
可查異常(編譯器要求必須處置的異常):正確的程序在運行中,很容易出現的、情理可容的異常情況。可查異常雖然是異常情況,但在必定程度上它的發生是能夠預計的,並且一旦發生這種異常情況,就必須採起某種方式進行處理。spa
除了RuntimeException及其子類之外,其餘的Exception類及其子類都屬於可查異常。這種異常的特色是Java編譯器會檢查它,也就是說,當程序中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句聲明拋出它,不然編譯不會經過。.net
不可查異常(編譯器不要求強制處置的異常):包括運行時異常(RuntimeException與其子類)和錯誤(Error)。
Exception 這種異常分兩大類運行時異常和非運行時異常(編譯異常)。程序中應當儘量去處理這些異常。
運行時異常:都是RuntimeException類及其子類異常,如NullPointerException(空指針異常)、IndexOutOfBoundsException(下標越界異常)等,這些異常是不檢查異常,程序中能夠選擇捕獲處理,也能夠不處理。這些異常通常是由程序邏輯錯誤引發的,程序應該從邏輯角度儘量避免這類異常的發生。
運行時異常的特色是Java編譯器不會檢查它,也就是說,當程序中可能出現這類異常,即便沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它,也會編譯經過。
非運行時異常 (編譯異常):是RuntimeException之外的異常,類型上都屬於Exception類及其子類。從程序語法角度講是必須進行處理的異常,若是不處理,程序就不能編譯經過。如IOException、SQLException等以及用戶自定義的Exception異常,通常狀況下不自定義檢查異常。
在 Java 應用程序中,異常處理機制爲:拋出異常,捕捉異常。
拋出異常:當一個方法出現錯誤引起異常時,方法建立異常對象並交付運行時系統,異常對象中包含了異常類型和異常出現時的程序狀態等異常信息。運行時系統負責尋找處置異常的代碼並執行。
捕獲異常:在方法拋出異常以後,運行時系統將轉爲尋找合適的異常處理器(exception handler)。潛在的異常處理器是異常發生時依次存留在調用棧中的方法的集合。當異常處理器所能處理的異常類型與方法拋出的異常類型相符時,即爲合適 的異常處理器。運行時系統從發生異常的方法開始,依次回查調用棧中的方法,直至找到含有合適異常處理器的方法並執行。當運行時系統遍歷調用棧而未找到合適 的異常處理器,則運行時系統終止。同時,意味着Java程序的終止。
對於運行時異常、錯誤或可查異常,Java技術所要求的異常處理方式有所不一樣。
因爲運行時異常的不可查性,爲了更合理、更容易地實現應用程序,Java規定,運行時異常將由Java運行時系統自動拋出,容許應用程序忽略運行時異常。
對於方法運行中可能出現的Error,當運行方法不欲捕捉時,Java容許該方法不作任何拋出聲明。由於,大多數Error異常屬於永遠不能被容許發生的情況,也屬於合理的應用程序不應捕捉的異常。
對於全部的可查異常,Java規定:一個方法必須捕捉,或者聲明拋出方法以外。也就是說,當一個方法選擇不捕捉可查異常時,它必須聲明將拋出異常。
可以捕捉異常的方法,須要提供相符類型的異常處理器。所捕捉的異常,多是因爲自身語句所引起並拋出的異常,也多是由某個調用的方法或者Java運行時 系統等拋出的異常。也就是說,一個方法所能捕捉的異常,必定是Java代碼在某處所拋出的異常。簡單地說,異常老是先被拋出,後被捕捉的。
任何Java代碼均可以拋出異常,如:本身編寫的代碼、來自Java開發環境包中代碼,或者Java運行時系統。不管是誰,均可以經過Java的throw語句拋出異常。
從方法中拋出的任何異常都必須使用throws子句。
捕捉異常經過try-catch語句或者try-catch-finally語句實現。
整體來講,Java規定:對於可查異常必須捕捉、或者聲明拋出。容許忽略不可查的RuntimeException和Error。
關於try-catch-finally捕獲異常時特殊狀況說明
1. finally中使用return語句,做爲一個5年的.Net開發者,第一次知道finally中還能夠加return,不過,不要驚訝!
finally中的return語句將會覆蓋方法原本的返回值,如下代碼將永遠返回false
1 boolean testEx1(){ 2 boolean ret = true; 3 try { 4 throw new Exception(); //1 5 //return true; //2 6 } catch (Exception e) { 7 System.out.println("testEx1, catch exception"); 8 return true; 9 } finally { 10 System.out.println("testEx1, finally; return value=" + ret); 11 return false; 12 } 13 14 }
finally中使用return將會抑制異常的冒泡傳輸
finally中不使用return情形:
1 public static void main(String[] args){ 2 try { 3 boolean result= testEx2(); 4 //System.out.println(result); 5 } catch (Exception e) { 6 System.out.println("main, catch exception"); 7 } finally { 8 System.out.println("main, finally"); 9 } 10 } 11 12 static boolean testEx2() throws Exception { 13 boolean ret = true; 14 try { 15 int result = 1/0; 16 return true; 17 } catch (Exception e) { 18 System.out.println("testEx2, catch exception"); 19 ret = false; 20 throw e; 21 } finally { 22 System.out.println("testEx2, finally; return value=" + ret); 23 //return ret; 24 } 25 26 }
輸出:
finally中使用return情形
1 static boolean testEx2() throws Exception { 2 boolean ret = true; 3 try { 4 int result = 1/0; 5 return true; 6 } catch (Exception e) { 7 System.out.println("testEx2, catch exception"); 8 ret = false; 9 throw e; 10 } finally { 11 System.out.println("testEx2, finally; return value=" + ret); 12 return ret; 13 } 14 }
輸出:
可見在testEx2方法finally中使用return時,main方法將捕獲不到異常,main方法認爲testEx2方法正常返回了。
2.finally拋出異常
finally中拋出異常將會覆蓋try-catch語句中拋出的異常
finally中不拋出異常情形:
1 public static void main(String[] args){ 2 try { 3 boolean result= testEx3(); 4 //System.out.println(result); 5 } catch (Exception e) { 6 System.out.println("main, catch exception"+e.getMessage()); 7 } finally { 8 System.out.println("main, finally"); 9 } 10 } 11 static boolean testEx3() throws Exception { 12 boolean ret = true; 13 try { 14 int result = 1/0; 15 return true; 16 } catch (Exception e) { 17 System.out.println("testEx2, catch exception"); 18 ret = false; 19 throw new Exception("testEx2 catch: throw exception"); 20 } finally { 21 System.out.println("testEx2, finally: return value=" + ret); 22 //throw new Exception("testEx2, finally: throw exception"); 23 } 24 25 }
上面代碼輸出結果:
修改爲在finally中拋出異常情形
1 static boolean testEx3() throws Exception { 2 boolean ret = true; 3 try { 4 int result = 1/0; 5 return true; 6 } catch (Exception e) { 7 System.out.println("testEx2, catch exception"); 8 ret = false; 9 throw new Exception("testEx2 catch: throw exception"); 10 } finally { 11 System.out.println("testEx2, finally: return value=" + ret); 12 throw new Exception("testEx2, finally: throw exception"); 13 } 14 15 }
輸出結果,與上面的狀況對比能夠發現,最終捕獲的是finally中拋出的異常。
常常在捕獲一個異常後又拋出另外一個異常,那麼若是但願將原來的異常信息保存下來,如何處理,這個時候就用到了異常鏈,在JDK1.4之前,程序員必須本身編寫代碼來保存原來的異常信息,如今全部Throwable的子類在構造器中均可以接受一個cause對象做爲參數,這個cause就是用來保存原始異常信息,裝經過把原始異常傳遞給新的異常,使得咱們能夠根據這個異常連追中到異常最初發生的位置。
下面是一個簡單示例:
1 public static void main(String[] args){ 2 try { 3 testEx5(); 4 } catch (Exception e) { 5 e.printStackTrace(); 6 } 7 } 8 9 static void testEx4() throws Exception{ 10 11 try { 12 int result = 1/0; 13 } catch (Exception e) { 14 throw new Exception("testEx4發生異常",e); 15 } 16 } 17 18 static void testEx5() throws Exception{ 19 20 try { 21 testEx4(); 22 } catch (Exception e) { 23 throw new Exception("testEx5發生異常",e); 24 } 25 }
輸出結果:
在Java中提供了一些異經常使用來描述常常發生的錯誤,對於這些異常,有的須要程序員進行捕獲處理或聲明拋出,有的是由Java虛擬機自動進行捕獲處理。Java中常見的異常類
java.lang.ArrayIndexOutOfBoundsException: 數組索引越界異常。當對數組的索引值爲負數或大於等於數組大小時拋出。
java.lang.ArithmeticException:算術條件異常。譬如:整數除零等。
java.lang.NullPointerException:空指針異常。當應用試圖在要求使用對象的地方使用了null時,拋出該異常。譬如:調用null對象的實例方法、訪問null對象的屬性、計算null對象的長度、使用throw語句拋出null等等
java.lang.ClassNotFoundException:找不到類異常。當應用試圖根據字符串形式的類名構造類,而在遍歷CLASSPAH以後找不到對應名稱的class文件時,拋出該異常。
java.lang.NegativeArraySizeException: 數組長度爲負異常
java.lang.ArrayStoreException: 數組中包含不兼容的值拋出的異常
java.lang.SecurityException: 安全性異常
java.lang.IllegalArgumentException: 非法參數異常
IOException:操做輸入流和輸出流時可能出現的異常。
EOFException: 文件已結束異常
FileNotFoundException:文件未找到異常
ClassCastException:類型轉換異常類
ArrayStoreException:數組中包含不兼容的值拋出的異常
SQLException:操做數據庫異常類
NoSuchFieldException:字段未找到異常
NoSuchMethodException:方法未找到拋出的異常
NumberFormatException:字符串轉換爲數字拋出的異常
StringIndexOutOfBoundsException:字符串索引超出範圍拋出的異常
IllegalAccessException:不容許訪問某類異常
InstantiationException:當應用程序試圖使用Class類中的newInstance()方法建立一個類的實例,而指定的類對象沒法被實例化時,拋出該異常
參考:
http://www.benchresources.net/exception-hierarchy-in-java/
https://www.cnblogs.com/itcui/p/6400499.html