这篇文章指出了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 阅读(303)
评论(0) 编辑 收藏