這篇文章指出了Java中checked Exception的一些缺點,提出應該在程序設計中避免使用checked Exception,對于需要處理checked Exception的代碼,可以使用ExceptionAdapter這個類對checked Exception進行包裝。這篇文章的概念和ExceptionAdapter這個類均源自Bruce Eckel的Does Java need Checked Exception。
Java
的
Exception
分為兩類,一類是
RuntimeException
及其子類,另外一類就是
checked Exception
。
Java
要求函數對沒有被
catch
處理掉的
checked Exception
,需要將其寫在函數的聲明部分。然而,這一要求常常給程序員帶來一些不必要的負擔。
?
為了避免在函數聲明中寫
throws
部分,在
Java
項目里面常常可以看到以下代碼用來‘吞掉’
Exception
:
?????? try{ ?????????? // ... ?????? }catch(Exceptionex){ ?????????? 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
:
publicclassExtendextendsBase{ ??? ??? publicvoidfoo()throwsExceptionB{ ?????? // ... ??? } } |
然而,這樣寫在
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();
???
}
}
|
?
參考文獻:
Bruce Eckel -- Does Java need Checked Exception
http://www.mindview.net/Etc/Discussions/CheckedExceptions
posted on 2007-01-12 20:02
???MengChuChen 閱讀(310)
評論(0) 編輯 收藏