避免在Java中使用Checked Exception

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

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

try {

// ...

} catch (Exception ex) {

ex.printStackTrace();

}

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

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

比這更糟糕的是,這有可能破壞類設計的open-close原則。簡單來 說,open-close原則是指當擴展一個模塊的時候,可以不影響其現有的client。open-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裏的類的時候。

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

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

  對於那些需要處理checked Exception的代碼,可以利用一個ExceptionAdapter的類把checked Exception包裝成一個RuntimeException拋出。ExceptionAdapter來自Bruce Eckel的Does 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();
}

}

發佈了103 篇原創文章 · 獲贊 17 · 訪問量 48萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章