【永恒的瞬间】
☜Give me hapy ☞

这篇文章指出了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)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: