天天看點

Java的異常捕獲處理

異常處理機制

在編寫程式時,經常要在可能出現錯誤的地方加上檢測的代碼,如進行x/y運算時,要檢測分母為0,資料為空,輸入的不是資料而是字元等。過多的分支會導緻程式的代碼加長,可讀性差。是以采用異常機制。

Java采用異常處理機制,将異常處理的程式代碼集中在一起,與正常的程式代碼分開,使得程式簡潔,并易于維護。

Java提供的是異常處理的抓抛模型。

Java程式的執行過程中如出現異常,會生成一個異常類對象,該異常對象将被送出給Java運作時系統,這個過程稱為抛出(throw)異常。

異常對象的生成

由虛拟機自動生成:程式運作過程中,虛拟機檢測到程式發生了問題,如果在目前代碼中沒有找到相應的處理程式,就會在背景自動建立一個對應異常類的執行個體對象并抛出——自動抛出。

由開發人員手動建立:Exception exception = new ClassCastException();——建立好的異常對象不抛出對程式沒有任何影響,和建立一個普通對象一樣。

如果一個方法内抛出異常,該異常對象會被抛給調用者方法中處理。如果異常沒有在調用者方法中處理,它繼續被抛給這個調用方法的上層方法。這個過程将一直繼續下去,直到異常被處理。這一過程稱為捕獲(catch)異常。

如果一個異常回到main()方法,并且main()也不處理,則程式運作終止。

程式員通常隻能處理Exception,而對Error無能為力。

捕獲異常

使用 try 和 catch 關鍵字可以捕獲異常。try/catch 代碼塊放在異常可能發生的地方。try/catch代碼塊中的代碼稱為保護代碼。使用try/catch的文法如下:

try {
   // 程式代碼
}catch(ExceptionName e) {
   //Catch 塊
}
           

try

捕獲異常的第一步是用try{…}語句塊標明捕獲異常的範圍,将可能出現異常的代碼放在try語句塊中。

catch (Exceptiontype e)

Catch 語句包含要捕獲異常類型的聲明。當保護代碼塊中發生一個異常時,try 後面的 catch 塊就會被檢查。如果發生的異常包含在 catch 塊中,異常會被傳遞到該 catch 塊,這和傳遞一個參數到方法是一樣。

在catch語句塊中是對異常對象進行處理的代碼。每個try語句塊可以伴随一個或多個catch語句,用于處理可能産生的不同類型的異常對象。

如果明确知道産生的是何種異常,可以用該異常類作為catch的參數,也可以用其父類作為catch的參數。比如:可以用ArithmeticException類作為參數的地方,就可以用RuntimeException類作為參數,或者用所有異常的父類Exception類作為參數。但不能是與ArithmeticException類無關的異常,如NullPointerException(catch中的語句将不會執行)。

捕獲異常的有關資訊:與其它對象一樣,可以通路一個異常對象的成員變量或調用它的方法。

 getMessage()   擷取異常資訊,傳回字元串

 printStackTrace()  擷取異常類名和異常資訊,以及異常出現在程式中的位置。傳回值void。

下面的例子中聲明有兩個元素的一個數組,當代碼試圖通路數組的第三個元素的時候就會抛出一個異常。

import java.io.*;
public class ExcepTest{
   public static void main(String args[]){
      try{
         // 可能産生異常的代碼,即需要被檢測的代碼
         int a[] = new int[2];
         System.out.println("擷取數組的第三個元素:" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){ // e用于接收try檢測到的異常對象
         System.out.println("抛出的異常:" + e);
         System.out.println("message:"+e.getMessage()); // 擷取的是異常的資訊
         System.out.println("toString:"+e.toString()); // 擷取的是異常的名字+異常的資訊
         e.printStackTrace(); // 列印異常在堆棧中資訊;異常名稱+異常資訊+異常的位置
      }
      System.out.println("try/catch代碼塊之後");
   }
}
           

執行結果為:

抛出的異常:java.lang.ArrayIndexOutOfBoundsException: 3
message:3
toString:java.lang.ArrayIndexOutOfBoundsException: 3
java.lang.ArrayIndexOutOfBoundsException: 3
	at ExcepTest.main(ExcepTest.java:6)
try/catch代碼塊之後
           

多重捕獲塊

一個 try 代碼塊後面跟随多個 catch 代碼塊的情況就叫多重捕獲。

多重捕獲塊的文法如下所示:

try{
   // 程式代碼
}catch(異常類型1 異常的變量名1){
  // 程式代碼
}catch(異常類型2 異常的變量名2){
  // 程式代碼
}catch(異常類型2 異常的變量名2){
  // 程式代碼
}
           

上面的代碼段包含了 3 個 catch塊。可以在 try 語句後面添加任意數量的 catch 塊。

如果保護代碼中發生異常,異常被抛給第一個 catch 塊。如果抛出異常的資料類型與  異常類型1  比對,它在這裡就會被捕獲。如果不比對,它會被傳遞給第二個 catch 塊。如此,直到異常被捕獲或者通過所有的 catch 塊。

try...catch...catch... 捕獲異常時,大的異常(Exception類)放在下方,小的異常放在上方,否則,在異常捕獲時,小的異常将不能被捕獲,因為全在大的異常類中捕獲到。即如果多個 catch 塊中的異常出現繼承關系,父類異常 catch 塊放在最下面。

finally

finally 代碼塊出現在 catch 代碼塊最後,文法如下:

try{
  // 程式代碼
}catch(異常類型1 異常的變量名1){
  // 程式代碼
}catch(異常類型2 異常的變量名2){
  // 程式代碼
}finally{ 
  // 程式代碼
}
           

捕獲異常的最後一步是通過finally語句為異常處理提供一個統一的出口,使得在控制流轉到程式的其它部分以前,能夠對程式的狀态作統一的管理。

不論在try代碼塊中是否發生了異常事件,catch語句是否執行,catch語句是否有異常,catch語句中是否有return,finally塊中的語句都會被執行。

finally主要用于關閉資源。無論是否發生異常,資源都必須進行關閉。隻有在finally之前執行了System.exit(0); 進而退出jvm的這種情況下finally才不執行。

finally語句和catch語句是任選的。

import java.io.*;
public class ExcepTest{
   public static void main(String args[]){
      int a[] = new int[2]; 
      try{
         // 可能産生異常的代碼,即需要被檢測的代碼
         System.out.println("擷取數組的第三個元素:" + a[3]);
      }catch(ArrayIndexOutOfBoundsException e){ // e用于接收try檢測到的異常對象
         System.out.println("抛出的異常:" + e);
      }finally{ // finally 關鍵字用來建立在 try 代碼塊後面執行的代碼塊。
         a[0] = 6;
         System.out.println("數組第一個元素的值:" +a[0]);
      }
   }
}
           

執行結果:

抛出的異常:java.lang.ArrayIndexOutOfBoundsException: 3
數組第一個元素的值:6
           

finally 代碼塊和 finalize()方法有什麼差別?

無論是否抛出異常, finally 代碼塊都會執行,它主要是用來釋放應用占用的資源。 finalize()方法是 Object 類的一個 protected 方法,它是在對象被垃圾回收之前由 Java 虛拟機來調用的。

使用異常捕獲時注意下面幾個事項:

1)catch 不能獨立于 try 存在。

2)在 try/catch 後面添加 finally 塊并非強制性要求的。

3)try 代碼後不能既沒 catch 塊也沒 finally 塊。

4)try, catch, finally 塊之間不能添加任何代碼。

不捕獲異常時的情況

前面使用的異常都是RuntimeException類或是它的子類,這些類的異常的特點是:即使沒有使用try和catch捕獲,Java自己也能捕獲,并且編譯通過 ( 但運作時會發生異常使得程式運作終止 )。

如果抛出的異常是IOException等類型的非運作時異常,則必須捕獲,否則編譯錯誤。也就是說,我們必須處理編譯時異常,将異常進行捕捉,轉化為運作時異常。

注意:    

1)異常處理完成以後,Exception對象會在下一個垃圾回收過程中被回收掉。

2)Java 語言定義了一些異常類在 java.lang 标準包中。标準運作時異常類的子類是最常見的異常類。由于 java.lang 包是預設加載到所有的 Java 程式的,是以大部分從運作時異常類繼承而來的異常都可以直接使用。

繼續閱讀