RuntimeException & Checked Exception

##Java 提供了兩種Exception 的模式,一種是執行的時候所產生的Exception (Runtime Exception),另外一種則是受控制的Exception (Checked Exception)。

##所有的Checked Exception 均從java.lang.Exception 繼承而來,而Runtime Exception 則繼承java.lang.RuntimeException 或java.lang.Error (實際上java.lang.RuntimeException 的上一層也是java.lang.Exception,這說明作爲exception兩者並沒有本質的區別,只是java語言本身從功能考慮有所區分,這才導致下面提到的不同點)。

##一個函數如果會拋出Checked Exception ,(這裏包含兩種情況,一個是函數本身拋出,另外一種是它調用的函數會拋出Checked Exception 但是它並沒有去catch這個exception),那在聲明此函數的時候必須標明throws XXXException()。而Runtime Exception不需要如此聲明

##邏輯上看,Runtime Exception 與Checked Exception 使用目的不一樣。一般而言,Checked Exception 表示這個Exception 必須要被處理,也就是說程序設計者應該已經知道可能會收到某個Exception(因爲要try catch住) ,所以程序設計者應該能也必須(或者標明throws XXXException()繼續拋出去,或者try catch處理,不然是編譯不過的)針對這些不同的Checked Exception 做出不同的處理。而Runtime Exception 通常會暗示着程序上的錯誤,這種錯誤會導致程序設計者無法處理,而造成程序無法繼續執行下去(可以try catch處理而避免程序掛掉,但是這常常會掩蓋問題所在)。


##checked exception由於必須被處理,會給程序員帶來額外的麻煩,試想一個函數a,它會調用到b1,b2...,b9一共9個函數,這些函數每個都會拋出 checked exception,而a函數裏面又沒有辦法處理這些exception,那在聲明a函數的時候就必須連寫9個throw xxxException,夠累的!!然而這僅僅是問題的一個方面,所以下面這篇文章試圖說服我們儘量使用runtime exception替代checked exception(前面提到可以try catch處理runtime exception,而避免程序掛掉,這也是這樣做的一個前提)。

這篇文章指出了Java中checked Exception的一些缺點,提出應該在程序設計中避免使用checked Exception,對於需要處理checked Exception的代碼,可以使用ExceptionAdapter這個類對checked Exception進行包裝。這篇文章的概念和ExceptionAdapter這個類均源自Bruce Eckel的Does Java need Checked Exception。


Java
Exception分爲兩類,一類是RuntimeException及其子類,另外一類就是checked ExceptionJava要求函數對沒有被catch處理掉的checked Exception,需要將其寫在函數的聲明部分。然而,這一要求常常給程序員帶來一些不必要的負擔。

 

 

爲了避免在函數聲明中寫throws部分,在Java項目裏面常常可以看到以下代碼用來‘吞掉’Exception

       try {

           // ...

       } catch (Exception ex) {

           ex.printStackTrace();

       }


這顯然不是一個好的處理Exception辦法,事實上,catch並處理一個Exception意味着讓程序從發生的錯誤(Exception)中恢復過來。從這種意義上說,已上的代碼只可能在一些很簡單的情況下工作而不帶來問題。

 

對於很多Exception,往往沒有去處理它並讓程序從錯誤中恢復出來的辦法,這時唯一能做的事情可能就是在界面上顯示一些提示信息給用戶。這種情況下讓程序拋出遇到的Exception是更爲合理的做法。然而,這樣做會使得一些函數的聲明急劇膨脹。一個函數可能需要聲明會拋出的78checked Exception,而且每個調用它的函數也需要同樣的聲明。

 

比這更糟糕的是,這有可能破壞類設計的open-close原則。簡單來說,open-close原則是指當擴展一個模塊的時候,可以不影響其現有的clientopen-close原則是通過繼承來實現的,當繼承一個類的時候,我們既擴展了這個類,也不會影響原有的client(因爲對這個類沒有改動)。

 

現在考慮下面這種情況,有一個父類Base

public class Base {

   

    public void foo() throws ExceptionA {

       // ...

    }

}


現在需要繼承Base這個類並重載foo這個方法,在新的實現中,foo可能拋出ExceptionB

public class Extend extends Base {

   

    public void foo() throws ExceptionB {

       // ...

    }

}


然而,這樣寫在Java裏面是不合法的,因爲Java把可能會拋出的Exception看作函數特徵的一部分,子類聲明拋出的Exception必須是父類的子集。

 

可以在Base類的foo方法中加入拋出ExceptionB的聲明,然而,這樣就破壞了open-close原則。而且,有時我們沒有辦法去修改父類,比如當重載一個Jdk裏的類的時候。

 

另一個可能的做法是在Extendfoo方法中catchExceptionB,然後構造一個ExceptionA並拋出。這是個可行的辦法但也只是一個權宜之計。

 

如果使用RuntimeException,這些問題都不會存在。這說明checked Exception並不是一個很實用的概念,也意味着在程序設計的時候,我們應該讓自己的Exception類繼承RuntimeException而不是Exception。(這和JDK的建議正好相反,但實踐證明這樣做代碼的質量更好。)

 

對於那些需要處理checked Exception的代碼,可以利用一個ExceptionAdapter的類把checked Exception包裝成一個RuntimeException拋出。ExceptionAdapter來自Bruce EckelDoes Java need Checked Exception這篇文章,在這裏的ExceptionAdapter是我根據JDK 1.4修改過的:

public class ExceptionAdapter extends RuntimeException {

   

    public ExceptionAdapter(Exception ex) {

       super(ex);

    }

   

    public void printStackTrace(java.io.PrintStream s) {

       getCause().printStackTrace(s);

    }

   

    public void printStackTrace(java.io.PrintWriter s) {

       getCause().printStackTrace(s);

    }

   

    // rethrow()的作用是把被包裝的Exception再次拋出。

    public void rethrow()

       throws Exception

    {

       throw (Exception) getCause();

    }

}

 

 

引用於:http://blog.csdn.net/daijialin/archive/2004/10/12/134078.aspx

http://hi.baidu.com/sansiloudeyu/blog/item/b85ca00274b87b0b4bfb51ac.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章