異常處理機制
一、什麽是異常
java的基本理念是“結構不佳的代碼不能運行”,在編譯期間並不能發現所有的錯誤,余下的問題必須在運行階段解決。異常處理是java中唯一正式的錯誤報告機制。異常情形是指阻止當前的方法或者作用域繼續執行的問題。在java中通過異常處理機制來處理程序運行期間出現的錯誤,提升程序的健壯性。
java中與使用其他對象一樣,在堆上創建對象來處理異常。針對不同的異常new出不同的異常對象。異常對象的根類是java.lang.Throwable類。在Java中定義了很多異常類(如OutOfMemoryError、NullPointerException、IndexOutOfBoundsException等),這些異常類分為兩大類:Error和Exception。Error即無法處理的異常,一旦發生終止程序的運行。Exception,是我們可以處理的異常。Exception包括hecked exception和unchecked exception兩類。
unchecked exception(非檢查異常),也稱運行時異常(RuntimeException),比如常見的NullPointerException、IndexOutOfBoundsException。對於運行時異常,java編譯器不要求必須進行異常捕獲處理或者拋出聲明,由程序員自行決定。
checked exception(檢查異常),也稱非運行時異常(運行時異常以外的異常就是非運行時異常),java編譯器強制程序員必須進行捕獲處理,比如常見的IOExeption和SQLException。對於非運行時異常如果不進行捕獲或者拋出聲明處理,編譯都不會通過。
在Java中,異常類的結構層次圖如下圖所示:
在Java中,所有異常類的父類是Throwable類,Error類是error類型異常的父類,Exception類是exception類型異常的父類,RuntimeException類是所有運行時異常的父類,RuntimeException以外的並且繼承Exception的類是非運行時異常。常見的異:NullPointerException、IndexOutOfBoundsException、ArrayIndexOutOfBoundsException等等。
異常匹配:拋出異常的時候,異常處理系統會按照代碼的書寫順序找出“最近”的處理程序,找到匹配的處理程序後,則認為異常得到了處理,然後不再繼續查找。查找的時候並不要求拋出的異常同處理程序聲明的異常完全匹配,派生類對象匹配其基類的處理程序。那麽Exception則是所有的異常類的基類,即可捕獲所有的異常。
把“受檢查異常“轉換為“不受檢查的異常”,可以在捕獲到的受檢查異常後,再次拋出一個不受檢查的異常。
二、異常的處理處理方式
1、捕獲
異常的捕獲主要使用try和catch關鍵字,被try塊包圍的代碼,表示這段代碼中可能出現異常,一旦發生異常,異常對象則被cathch捕獲,然後在catch塊中進行處理。如下:
1 public class Demo5 { 2 public static void main(String[] args) { 3 try { 4 int i=10/0; 5 System.out.println(i); 6 } catch (ArithmeticException e) { 7 e.printStackTrace(System.err); 8 } 9 } 10 } 11 輸出的結果: 12 java.lang.ArithmeticException: / by zero 13 at com.sun.lp.demo.Demo5.main(Demo5.java:18)
2、拋出
拋出是異常處理的另外一種方式,顧名思義,一旦發生異常,將異常拋出去,處理的關鍵字是throw和throws,如下:
public class Demo5 { public void test() throws Exception{ try { int i = 10/0; System.out.println(i); } catch (Exception e) { //捕獲到異常,不處理,將其拋出 throw e; } } public static void main(String[] args) { try { Demo5 demo5 = new Demo5(); demo5.test(); } catch (Exception e) { e.printStackTrace(System.err); } } }
結果輸出:
java.lang.ArithmeticException: / by zero at com.sun.lp.demo.Demo5.test(Demo5.java:6) at com.sun.lp.demo.Demo5.main(Demo5.java:17)
三、自定義異常
不拘泥於java中已有的異常對象,java提供的異常體系不可能預見所有的異常。所以java提供自定義異常的途徑。自定義異常必須從已有異常類的基礎上繼承和拓展。建立新的異常最簡單的方法是讓編譯器為你產生默認的構造器
1 public class Demo { 2 3 public void test() throws MyException{ 4 System.out.println("Exception is from test()"); 5 throw new MyException(); 6 } 7 8 public static void main(String[] args) { 9 try { 10 Demo demo = new Demo(); 11 demo.test(); 12 } catch (Exception e) { 13 System.out.println("get a Exception"); 14 e.printStackTrace(System.err); 15 } 16 17 } 18 19 } 20 21 class MyException extends Exception{ 22 MyException(){ 23 System.out.println("自定義異常類"); 24 } 25 }
輸出結果:
Exception is from test() 自定義異常類 get a Exception com.test.demo.MyException at com.test.demo.Demo.test(Demo.java:5) at com.test.demo.Demo.main(Demo.java:11)
四、使用finally進行清理
對於一些代碼,無論try塊中的異常是否拋出,它們都能執行,達到這個效果可以使用finally子句。finally子句總能運行。
1 public class FinallyDemo { 2 public static int count=0; 3 public static void main(String[] args) { 4 while(true){ 5 try { 6 if(count++==0) 7 throw new SimpleException(); 8 System.out.println("No Exception"); 9 } catch (SimpleException e) { 10 System.out.println("get a SimpleException"); 11 }finally{ 12 System.out.println("finally 子句執行"); 13 if(count==2) break; 14 } 15 } 16 } 17 } 18 class SimpleException extends Exception{ 19 SimpleException(){ 20 super(); 21 } 22 }
輸出結果:
get a SimpleException finally 子句執行 No Exception finally 子句執行
五、幾個關鍵字的使用
1.try關鍵字用來包圍可能會出現異常的邏輯代碼,它單獨無法使用,必須配合catch或者finally使用。三個塊執行的順序為try—>catch—>finally。Java編譯器允許的組合使用形式只有以下三種形式:
try...catch...; try....finally......; try....catch...finally...
2.throws和thow關鍵字
throws出現在方法的聲明中,表示該方法可能會拋出的異常,然後交給上層調用它的方法程序處理,允許throws後面跟著多個異常類型。
throw一般用於程序出現某種邏輯,程序員主動拋出指定的異常對象,throw主要出現在方法體中,拋出的異常對象可以進行向上轉型。
3.由於垃圾回收機制的存在,finally主要是把除內存資源之外的資源恢復到它們的初始狀態,例如:關閉文件流,網絡聯機,關閉數據庫連接等等。
六、異常使用指南
1)在恰當的級別處理問題(在知道如何處理的情況下才捕獲異常)
2)解決問題並重新調用產生異常的方法
3)進行少許的修補,然後繞過異常發生的地方繼續執行
4)用別的數據進行計算,以代替方法預計會返回的值
5)把當前運行環境下能做的事情盡量做完,然後把相同的異常拋出到更高層
6)把當前運行環境下能做的事情盡量做完,然後把不相同的異常拋出到更高層
7)終止程序
8)進行簡化
9)讓類庫和程序更安全。
異常處理機制