Exception

Diy_os發表於2015-10-29
異常的概念: 
1.是java提供的同於處理程式中錯誤的一種機制
2.所謂的錯誤是程式執行過程中發生的一些異常事件(如:除0,陣列下標越界,所要讀取的檔案不存在
3.設計良好的程式應該在異常發生時提供處理這些錯誤的方法,使得程式不會因為這些異常發生阻斷或者產生不可預知的結果
4.java程式執行的過程中如出現異常事件,可以產生一個異常類物件,該異常物件封裝了異常事件的資訊並將該資訊
提交給java執行時系統,這個過程稱為丟擲異常(throw)
5.當java執行系統接收到異常物件的時候,會尋找能處理這一異常的程式碼並將當前的異常物件交給其處理,這一過程稱為捕獲異常(catch)

Java異常的始祖是Throwable,它有兩個重要的子類:Exception(異常)和 Error(錯誤),二者都是 Java 異常處理的重要子類,各自都包含大量子類。這兩個類繼承了類Throwable,具體可以見API文件(
),上面說明的很清楚,為了更好地理解概念,下面給出了異常類層次結構圖:

簡單的分析上圖:
Error:稱為錯誤,由java虛擬機器生成並丟擲,包括動態連結失敗,虛擬機器錯誤等,程式不對其作任何處理
Exception:所有異常類的父類,其子類對應了各種各樣可能出現的異常事件,一般需要使用者顯示的宣告或者捕獲
Runtime Exception:一類特殊的異常,如被0除,陣列下標超過範圍等,其產生比較繁瑣,處理麻煩,如果顯示的宣告
或捕獲將會對程式可讀性和執行效率影響很大。因此由系統自動檢測並將它們交給預設的異常處理程式(使用者可以不必對其處理)

下面不重點介紹Error,因為其是程式無法處理的錯誤,一般因為程式出現嚴重錯誤而導致。這個和Exception不同,它可以被程式處理的。
   
Exception 類有一個重要的子類 RuntimeException。RuntimeException 類及其子類表示“JVM 常用操作”引發的錯誤。例如,若試圖使用空值物件引用(NullPointerException),除數為零ArithmeticException),陣列越界(ArrayIndexOutOfBoundException)
 
Java的異常(包括Exception和Error)分為可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。
可查異常(編譯器要求必須處置的異常):正確的程式在執行中,很容易出現的、情理可容的異常狀況。可查異常雖然是異常狀況,但在一定程度上它的發生是可以預計的,而且一旦發生這種異常狀況,就必須採取某種方式進行處理。
不可查異常(編譯器不要求強制處置的異常):包括執行時異常(RuntimeException與其子類)和錯誤(Error)。
 除了RuntimeException及其子類以外,其他的Exception類及其子類都屬於可查異常。這種異常的特點是Java編譯器會檢查它,也就是說,當程式中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句宣告丟擲它,否則編譯不會透過。

  Exception 這種異常分兩大類執行時異常和非執行時異常(編譯異常)。程式中應當儘可能去處理這些異常。
執行時異常:都是RuntimeException類及其子類異常,如NullPointerException(空指標異常)、IndexOutOfBoundsException(下標越界異常)等,這些異常是不檢查異常,程式中可以選擇捕獲處理,也可以不處理。這些異常一般是由程式邏輯錯誤引起的,程式應該從邏輯角度儘可能避免這類異常的發生。
執行時異常的特點是Java編譯器不會檢查它,也就是說,當程式中可能出現這類異常,即使沒有用try-catch語句捕獲它,也沒有用throws子句宣告丟擲它,也會編譯透過。
非執行時異常 (編譯異常):是RuntimeException以外的異常,型別上都屬於Exception類及其子類。從程式語法角度講是必須進行處理的異常,如果不處理,程式就不能編譯透過。如IOException、SQLException等以及使用者自定義的Exception異常,一般情況下不自定義檢查異常。


Java中是如何處理異常呢,異常先被丟擲,然後被捕獲。
涉及到這幾個關鍵字:try,catch,throws,throw,finally
簡單的分析這幾個關鍵字:
try語句:
try{.....}語句指定了一段程式碼,該段程式碼就是一次捕獲並處理例外的範圍
在執行過程中,該段程式碼可能會產生並丟擲一種或幾種型別的異常物件,它後面的catch
語句要分別對這些異常做出相應的處理
如果沒有產生例外,所有的catch程式碼段都被略過不執行

catch語句:
1.在catch語句塊中是對異常進行處理的程式碼,每個try語句可以伴隨一個或者多個catch語句,用於處理可能差生的
不同型別的異常物件
2.在catch中宣告的異常物件(catch(someException))封裝了異常事件發生的資訊,在
catch語句塊中可以使用這個物件的一些方法獲取這些資訊
3.getMessage()方法,用來得到有相關異常事件的資訊;printStackTrace()方法用來跟蹤異常
事件發生時執行堆疊的內容
final語句:
1.finally語句為異常處理提供一個統一的出口,使得控制流程轉到
程式其他部分的以前,能夠對程式的狀態作統一的管理
2.無論try所指定的程式塊中是否丟擲例外,finally所指定額程式碼都要被執行
3.通常在finally語句中可以進行資源的清除的工作,比如:
關閉開啟的檔案;刪除臨時檔案;.....
throws:
 如果一個方法可能會出現異常,但沒有能力處理這種異常,可以在方法宣告處用throws子句來宣告丟擲異常。
throw:
throw總是出現在函式體中,用來丟擲一個Throwable型別的異常。程式會在throw語句後立即終止,它後面的語句執行不到,然後在包含它的所有try塊中(可能在上層呼叫函式中)從裡向外尋找含有與其匹配的catch子句的try塊。

下面透過被除數為0的小程式來說明這個上面的幾個關鍵字:

點選(此處)摺疊或開啟

  1. class Exception{
  2. public static void main(String[] args)
  3.      {
  4.      try
  5.      {
  6.      int a = 3;
  7.      int b = 0;

  8.      // 這塊程式碼出現了異常
  9.      c = a / b;

  10.      // 那麼異常之後的程式碼都不會被執行
  11.      System.out.println("Hello World");
  12.      }
  13.      catch (ArithmeticException e)
  14.      {
  15.      e.printStackTrace();
  16.      }
  17.     
  18.     }
上面我們用try{....}catch{}塊捕獲異常,並用ArithmeticException物件呼叫printStackTrace()方法用來跟蹤異常事件發生時執行堆疊的內容,關於ArithmeticException異常類,詳見
如果出現異常了,那麼try中出現異常語句的下一條語句就不會執行,而是跳到catch語句,來處理這個異常,當然一個try語句後,可以跟多個catch語句,當我們捕獲到異常,如果我們可以處理,那儘量去處理這種異常,而不是catch語句中什麼操作也沒有,這種程式設計習慣我們要摒棄,有能力處理異常一定要處理,沒有能力處理則拋給它的呼叫者處理,而不能對這個異常不做任何處理。


點選(此處)摺疊或開啟

  1. class Exception{
  2. public static void main(String[] args)
  3.      {
  4.      int c = 0;
  5.      try
  6.      {
  7.      int a = 3;
  8.      int b = 0;

  9.      // 這塊程式碼出現了異常
  10.      c = a / b;

  11.      // 那麼異常之後的程式碼都不會被執行
  12.      System.out.println("Hello World");
  13.      }
  14.      catch (ArithmeticException e)
  15.      {
  16.      e.printStackTrace();
  17.      }
  18.      finally
  19.      {
  20.      //不管有沒有發生異常,finally語句塊都會被執行
  21.      System.out.println("檢查程式異常");
  22.      }

  23.      System.out.println(c);
  24.      // 當b為0時,有異常,輸出為c的初始值0
  25.      }
  26.     }
上面語句新增了finally語句,不管程式是否出現異常,那麼finally語句都會被執行,當然關於finally的好處上文已經給出,該處為示例。

如果用finally語句,上面的寫法一定是最好的麼?修改上面的程式碼,如下圖:

點選(此處)摺疊或開啟

  1. class ExceptionTest{
  2.     
  3.     
  4.      public static void main(String[] args){
  5.         
  6.          try{
  7.             
  8.          try{
  9.              int a =3;
  10.              int b =0;
  11.              int c = a/b;
  12.          }finally{
  13.             
  14.             System.out.println("檢查異常");
  15.          }
  16.   }catch (ArithmeticException e) {
  17.             
  18.             e.printStackTrace();
  19.          }
  20.      }
  21. }

運用try/finally,try/catch語句,是不是使上面程式碼看起來更清晰呢?內層的try/finally語句職責是為了關閉開啟檔案,刪除臨時檔案,關閉與資料庫的連線,而外層try/catch語句,是為了檢查異常帶來的錯誤。上面程式碼如果沒有異常發生,則只會列印finally語句中的執行內容。但是上面的寫法並不一定不帶來一些問題,比如try語句的返回值會被finally語句的返回值覆蓋等。



點選(此處)摺疊或開啟

  1. class ExceptionTest{
  2.  public void f() throws ArithmeticException{
  3.         
  4.         int a =3;
  5.         int b = 0;
  6.         int c = a/b;
  7.         //System.out.println(c);
  8.     throw new ArithmeticException();
  9.         
  10.     }
  11.     
  12.      public void m() throws Exception{
  13.         
  14.          f();
  15.          throw new Exception();
  16.      }
  17.     
  18.      public void n() throws Exception{
  19.         
  20.          m();
  21.          throw new Exception();
  22.      }
  23.    
  24.     public static void main(String[] args) throws Exception{
  25.         
  26.     
  27.         ExceptionTest w = new ExceptionTest();
  28.         try{
  29.         w.n();
  30.         
  31.         }catch(ArithmeticException e){
  32.             
  33.             e.printStackTrace();
  34.         }
  35.      }
  36. }
上面函式中出現異常,一層一層的丟擲,最終由主函式來處理,這種不是很好的理想的處理方式。當然我們希望這樣來處理:


點選(此處)摺疊或開啟

  1. class ExceptionTest{
  2.  public void f() throws ArithmeticException{
  3.          
  4.         int a =3;
  5.         int b = 0;
  6.         int c = a/b;
  7.         //System.out.println(c);
  8.     throw new ArithmeticException();
  9.         
  10.     }
  11.   
  12.     public static void main(String[] args){
  13.         
  14.      
  15.         ExceptionTest w = new ExceptionTest();
  16.         try{
  17.         w.f();
  18.         
  19.         }catch(ArithmeticException e){
  20.             
  21.             e.printStackTrace();
  22.         }
  23.      }
  24. }


如何自定義異常類呢?
1.透過繼承java.lang.Exception宣告自己的異常類或者其他的異常類(如果繼承的是RuntimeException的話,可以不捕獲)
2.在方法適當的位置生成自定義的例項,並用throw語句丟擲
3.在方法的宣告部分用throws語句宣告該方法可能丟擲的異常
上面可以透過繼承ArithmeticException,來重寫其中的方法,來自定義類,讀者可以查閱API來嘗試該步操作。


下面談一下,如果一個類繼承了一個出現異常類,那麼如何重寫其中的方法呢?
謹記這一條:重寫方法需要丟擲與原方法所丟擲異常型別一致異常或者不丟擲異常
class A{
public void method() throws IOException{.....}
}
class B1 extends A{   //錯誤
public void method() throws FileNoFoundException{....}
}
class B2 extends A{   //錯誤
public void method() throws Exception(){......}
}
class B3 extends A{  //正確
public void method(){...}
}
class B4 extends A{ //錯誤
public void method() throws IOException,MyException{....}
class B5 extends A{ //正確
public void method()throws IOException{.....}
}


點選(此處)摺疊或開啟

  1. class ExceptionTest{

  2.      public void f() throws ArithmeticException{
  3.         
  4.         int a =3;
  5.         int b = 0;
  6.         int c = a/b;
  7.         //System.out.println(c)
  8.     throw new ArithmeticException();
  9.         
  10.     }
  11.     
  12. }

  13. public class Exception1 extends ExceptionTest{
  14.     
  15.     public void f(){
  16.         
  17.         System.out.println("wang");
  18.     }
  19.     
  20.     public static void main(String[] args){
  21.         
  22.         Exception1 w = new Exception1();
  23.         w.f();
  24.     }
  25. }
上面完全正常,讀者感興趣可以完成其他的操作,這裡不贅述。

上面文章簡單的介紹Java異常,如有錯誤之處,請指正,謝謝!

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29876893/viewspace-1818695/,如需轉載,請註明出處,否則將追究法律責任。

相關文章