try...catch...finally我們經常在代碼中用到了,一直覺得這個東西沒有太大的用處。因爲在開發中,我們總是很堅信我們的代碼是不會出錯的。這樣說來,問題就來了,一旦我們的系統出了錯,沒有它們,系統就會崩潰,反映給用戶,用戶就不會再用這個系統。
一、Java異常
異常指不期而至的各種狀況,如:文件找不到、網絡連接失敗、空指針、類找不到、非法參數等等。異常是一個事件,它發生在異常運行期間,干擾了正常的指令流程。Java通過API中的Throwable類的衆多子類描述各種不同的異常。因此,Java異常也是異常,是Throwbale子類的實例。
Java異常類層次結構圖
從圖中我們可以看到,Throwable作爲一個類,有兩個重要的子類:
Error(錯誤):程序是無法處理的,一旦遇到,系統崩潰,無法繼續運行,表示運行應用程序中較嚴重的問題。
Exception(異常):程序本身可以進行處理的異常。一般可以分爲兩類:Io流出和運行異常。
二、處理異常機制
在Java應用程序中,異常處理機制:拋出異常,捕捉異常。
拋出異常:當一個方法出現錯誤引發宜昌市,方法創建異常對象並交付運行時系統,異常對象中包含了異常類型和異常出現時的程序狀態等異常信息。通常我們用throw將異常拋給調用它的方法。
捕捉異常:在方法拋出一場之後,運行時系統將轉爲尋找合適的異常處理器。在方法拋出異常之後,運行時系統將轉爲尋找合適的異常處理器(exception handler)。潛在的異常處理器是異常發生時依次存留在調用棧中的方法的集合。當異常處理器所能處理的異常類型與方法拋出的異常類型相符時,即爲合適 的異常處理器。運行時系統從發生異常的方法開始,依次回查調用棧中的方法,直至找到含有合適異常處理器的方法並執行。當運行時系統遍歷調用棧而未找到合適 的異常處理器,則運行時系統終止。同時,意味着Java程序的終止。
對於運行時異常、錯誤或可查異常,Java技術所要求的異常處理方式有所不同。
由於運行時異常的不可查性,爲了更合理、更容易地實現應用程序,Java規定,運行時異常將由Java運行時系統自動拋出,允許應用程序忽略運行時異常。
對於方法運行中可能出現的Error,當運行方法不欲捕捉時,Java允許該方法不做任何拋出聲明。因爲,大多數Error異常屬於永遠不能被允許發生的狀況,也屬於合理的應用程序不該捕捉的異常。
對於所有的可查異常,Java規定:一個方法必須捕捉,或者聲明拋出方法之外。也就是說,當一個方法選擇不捕捉可查異常時,它必須聲明將拋出異常。
一個方法所能捕捉的異常,一定是java代碼在某處拋出的異常。簡單地說,異常總是先被拋出,後被捕捉的。
一個方法中拋出的任何異常都必須使用throws字句。
1、捕捉異常
通常使用try-catch或者try-catch-finally語句實現。
(1)、try-catch
實例:
- public class TestException {
- public static void main(String[] args) {
- int[] intArray = new int[3];
- try {
- for (int i = 0; i <= intArray.length; i++) {
- intArray[i] = i;
- System.out.println("intArray[" + i + "] = " + intArray[i]);
- System.out.println("intArray[" + i + "]模 " + (i - 2) + "的值: "
- + intArray[i] % (i - 2));
- }
- } catch (ArrayIndexOutOfBoundsException e) {
- System.out.println("intArray數組下標越界異常。");
- } catch (ArithmeticException e) {
- System.out.println("除數爲0異常。");
- }
- System.out.println("程序正常結束。");
- }
- }
上面的代碼中捕獲兩個錯誤:除數爲0和數組下標越界異常。運行結果:
intArray[0] = 0
intArray[0]模 -2的值: 0
intArray[1] = 1
intArray[1]模 -1的值: 0
intArray[2] = 2
除數爲0異常。
程序正常結束。
我們運行就會發現當捕捉到第一個錯誤的時候,系統將不再執行try之後的代碼,運行先捕捉到除數爲0的錯誤,因此,而後的處理結束,就以爲這整個try-catch語句結束。
Java通過異常類描述異常類型,異常類的層次結構如圖1所示。對於有多個catch子句的異常程序而言,應該儘量將捕獲底層異常類的catch子 句放在前面,同時儘量將捕獲相對高層的異常類的catch子句放在後面。否則,捕獲底層異常類的catch子句將可能會被屏蔽。
(2)、try-catch-finally
不管catch有沒有異常捕獲,finally都是會運行的。
圖示try-catch-finally語句的執行:
2、拋出異常
(1)、throws拋出異常
如果一個方法可能會出現異常,但沒有能力處理這種異常,可以在方法聲明處用throws子句來聲明拋出異常。例如汽車在運行時可能會出現故障,汽車本身沒辦法處理這個故障,那就讓開車的人來處理。
throws語句用在方法定義時聲明該方法要拋出的異常類型,如果拋出的是Exception異常類型,則該方法被聲明爲拋出所有的異常。多個異常可使用逗號分割。throws語句的語法格式爲:
- methodname throws Exception1,Exception2,..,ExceptionN
- {
- }
使用throws關鍵字將異常拋給調用者後,如果調用者不想處理該異常,可以繼續向上拋出,但最終要有能夠處理該異常的調用者。
一般,我們使用異常,將異常拋給UI,通過Error頁面,進行處理,這樣給用戶體驗會好一些。
(2)、throw拋出異常
throw通常出現在函數體中,用來拋出一個Throwable類型的異常。程序會在throw語句會立即終止,它之後的代碼是不會執行的。
- <span style="font-family:KaiTi_GB2312;font-size:18px;">package Test;
- import java.lang.Exception;
- public class TestException {
- static int quotient(int x, int y) throws MyException { // 定義方法拋出異常
- if (y < 0) { // 判斷參數是否小於0
- throw new MyException("除數不能是負數"); // 異常信息
- }
- return x/y; // 返回值
- }
- public static void main(String args[]) { // 主方法
- int a =3;
- int b =0;
- try { // try語句包含可能發生異常的語句
- int result = quotient(a, b); // 調用方法quotient()
- } catch (MyException e) { // 處理自定義異常
- System.out.println(e.getMessage()); // 輸出異常信息
- } catch (ArithmeticException e) { // 處理ArithmeticException異常
- System.out.println("除數不能爲0"); // 輸出提示信息
- } catch (Exception e) { // 處理其他異常
- System.out.println("程序發生了其他的異常"); // 輸出提示信息
- }
- }
- }
- class MyException extends Exception { // 創建自定義異常類
- String message; // 定義String類型變量
- public MyException(String ErrorMessagr) { // 父類方法
- message = ErrorMessagr;
- }
- public String getMessage() { // 覆蓋getMessage()方法
- return message;
- }
- } </span>
要注意的是,throw 拋出的只能夠是可拋出類Throwable 或者其子類的實例對象。
如果拋出了檢查異常,則還應該在方法頭部聲明方法可能拋出的異常類型。該方法的調用者也必須檢查處理拋出的異常。
總結:
異常在程序中是不可以被取代的,更不能不寫,這是很危險的一件事情,異常體現了一個程序員的專業性,更能體現一個程序員的全局觀。