在一些傳統的語言(如C語言中)java
if語句來判斷是否出現了例外函數
全程變量ErrNospa
但這有幾個缺點code
正常處理與異常處理的代碼一樣處理對象
可讀性(readability)差繼承
每次調用一個方法時都進行錯誤檢查圖片
可維護性( maintainability )差錯誤由誰處理不請字符串
職責不清get
Java中處理異常包括input
拋出(throw)異常
運行時系統在調用棧中查找
從生成異常的方法開始進行回溯,直到找到:
捕獲(catch) 異常的代碼
調用過程以下所示:
沒有使用Java異常處理機制
public class Test { public static void main(String [] args){ for(int i = 0; i < 2;i++){ System.out.print(i + " "); System.out.println(1/0);//throw an exception. } } }
運行結果:
0 Exception in thread "main" java.lang.ArithmeticException: / by zero
1/0明顯非法,因此產生了異常ArithmeticException對象,這個對象是Exception的子類。
如下開始用異常處理機制捕獲該異常:
public class Test { public static void main(String [] args){ for(int i = 0; i < 2;i++){ System.out.print(i + " "); try{ System.out.println(1/0);//An exception will throw from here. } catch(Exception ex){//在這裏,這個Exception 其實就是ArithmeticException //這裏用到了程序運行時的多態思想。 //實際中應指定具體的做爲ex的類型,更加有針對性。 System.out.println("exception handling...");// } } } }
運行結果:
0 exception handling... 1 exception handling...
這樣確實能捕獲到相應的異常對象。儘管什麼也沒作(只是打印字符串),卻讓編譯器再也不報告以前的異常。由於上述catch(type ex){...}
就是負責處理異常。
當捕獲到異常後,程序的運行過程會怎樣?
public class Test2 { public static void main(String[] args){ try{ for (int i = 0; i< 2; i++){ System.out.print(i + " "); System.out.println(1/0);//exception being thrown from here.Then it wil jump directly to the corresponding catch block. System.out.println("This line is supposed to be ignored"); } } //handling the exception. catch(Exception ex){ System.out.println("Exception handling..."); } System.out.println("End of the main()"); } }
運行結果:
0 exception handling... End of the main()
當for
不可能循環到i = 2
;由於在i = 1
時已經拋出了異常。只要產生了異常,轉入對應的catch(type ex){...}
。catch(type ex)
必須在參數裏面說明捕獲的對象是哪類型的。throw
語句就像一個調用函數,當程序運行中拋出了一個異常對象,就會調用對應的catch(type ex){}
來處理。但它又不像調用函數。由於在調用完後,它不會返回到throw
語句,而是接着catch以後的語句。因此System.out.println("This line is supposed to be ignored");
這條語句被沒有執行;for
循環也至關於被中斷了。
拋出異常
throw 異常對象;
捕獲異常
try{ 語句組 } catch(異常類名 異常形式參數名){ 異常處理語句組; } catch(異常類名 異常形式參數名){ 異常處理語句組; } finally{ 異常處理語句組; }
其中,catch語句能夠0至多個,能夠沒有finally語句
Throwable
Error: JVM的錯誤(通常來講,咱們很難處理這裏異常)
Exception: 異常(重點關注)
注:通常所說的異常,是指Exception及其子類
構造方法
public Exception(); public Exception(String message); Exception(String message, Throwable cause) ;
方法
getMessage() getCause() printStackTrace()
仍然是沒有使用Java的異常處理機制:
import java.util.Scanner; public class QuotientWithMethod { public static int quotient(int num1, int num2){ if(num2 == 0){ log("Divisor cannot be zero"); System.exit(1); } return num1/num2; } public static void log(String s){ System.out.println(s); } public static void main(String[] args){ Scanner input = new Scanner(System.in); //prompt user to enter two integers int num1 = input.nextInt(); int num2 = input.nextInt(); int result = quotient(num1,num2);//調用函數 System.out.println(num1 + "/" + num2 + "is" + result ); } }
運行結果
input two numbers: 1 0 Divisor cannot be zero
在沒用使用異常處理機制的狀況下,出現了異常狀況的話,在被調用的函數中,處理異常狀況——這裏是直接退出了程序;
用異常處理機制的好處是職責分明:被調函數中拋出異常,主調函數中負責處理異常。
import java.util.Scanner; public class QuotientWithException { public static int quotient(int num1, int num2){ if(num2 == 0){ throw new ArithmeticException("Divisor cannot be zero");//用關鍵字throw拋出異常對象,這裏是調用構造器來新建對象 }//但不作處理 return num1/num2; } public static void main(String[] args){ Scanner input = new Scanner(System.in); System.out.println("input two numbers:"); int num1 = input.nextInt(); int num2 = input.nextInt(); boolean goOn = true; do { try { int result = quotient(num1, num2); System.out.println("num1" +"/" + "num2" + "is" +result); goOn = false; } //職責分明;一個負責拋出異常,一個負責處理異常. catch(ArithmeticException ex){ //在主調函數中處理異常 System.out.println("Exception occur:" + "Divisor cannot be zero. \n input again,please:"); num1 = input.nextInt(); num2 = input.nextInt(); //int result = quotient(num1, num2); //System.out.println("num1" +"/" + "num2" + "is" +result); } }while(goOn); //處理後,進入catch{}後的語句. System.out.println("End of main()."); } }
運行結果
input two numbers: 1 0 Exception occur:Divisor cannot be zero. input again,please: 1 1 num1/num2is1 End of main().
在被調函數中,只負責拋出異常:throw new ArithmeticException("Divisor cannot be zero");
,主調函數中catch(ArithmeticException ex){...}
指定將要捕獲的對象的類型,並作相應的處理,這裏要求從新輸入。
子類異常要排在父類異常的前面,也就是先處理具體的異常,後處理抽象的異常。
finally語句,不管是否有異常都要執行,即便其中有break,return等語句
在編譯時,finally部分代碼生成了多遍
RuntimeException及其子類,能夠不明確處理;不然,稱爲受檢的異常(checked Exception)
RuntimeException, Error, and their subclasses are known as unchecked exceptions. All other exceptions are known as checked exceptions, meaning that the compiler forces the programmer to check and deal with them in a try-catch block or declare it in the method header.--Introduction to Java
對於受檢的異常(checked Exception),要求明確進行語法處理:
要麼捕(catch)
要麼拋(throws):在方法的簽名後面用throws xxxx來聲明
在子類中,若是要覆蓋父類的一個方法,若父類中的方法聲明瞭 throws異常,則子類的方法也能夠throws異常
能夠拋出子類異常(更具體的異常),但不能拋出更通常的異常
建立用戶自定義異常時
繼承自Exception類或某個子Exception類
定義屬性和方法,或重載父類的方法
這樣getMessage()
, toString()
, printStackTrace()
都會從Exception
繼承下來。
對於異常,不只要進行捕獲處理,有時候還須要將此異常進一步傳遞給調用者,以 便讓調用者也能感覺到這種異常。這時能夠在catch語句塊或finally語句塊中採起,如下三種方式:
將當前捕獲的異常再次拋出:throw e;
從新生成一個異常,並拋出,如: throw new Exception("some message");
從新生成並拋出一個新異常,該異常中包含了當前異常的信息,如:throw new Exception("some message",e);
用e.getCause()
來獲得內部異常