nbsp;new StringWriter();
e.printStackTrace(new PrintWriter(sw));
stackTrace = sw.toString();
}
public void printStackTrace() {
printStackTrace(System.err);
}
public void printStackTrace(java.io.PrintStream s) {
synchronized(s) {
s.print(getClass().getName() + ": ");
s.print(stackTrace);
}
}
public void printStackTrace(java.io.PrintWriter s) {
synchronized(s) {
s.print(getClass().getName() + ": ");
s.print(stackTrace);
}
}
public void rethrow() { throw originalException; }
}
如果查看 Eckel 的 Web 站点上的讨论,您将会发现回应者是严重分裂的。一些人认为他的提议是荒谬的;一些人认为这是一个重要的思想。(我的观点是,尽管恰当地使用异常确实是很难的,并且对异常用不好的例子大量存在,但是大多数赞同他的人是因为错误的原因才这样做的,这与一个政客位于一个可以随便获取巧克力的平台上参选将会获得十岁孩子的大量选票的情况具有相似之处。)
Rod Johnson 是 J2EE Design and Development (请参阅 参考
资料) 的作者,这是我所读过的关于 Java 开发,J2EE 等方面的最好的书籍之一。他采取一个不太激进的方法。他列举了异常的多个类别,并且为每个类别确定一个策略。一些异常本质上是次要的返回代码(它通常指示违反业务规则),而一些异常则是“发生某种可怕错误”(例如数据库连接失败)的变种。Johnson 提倡对于第一种类别的异常(可选的返回代码)使用检查型异常,而对于后者使用运行时异常。在“发生某种可怕错误”的类别中,其动机是简单地认识到没有调用者能够有效地处理该异常,因此它也可能以各种方式沿着栈向上扩散而对于中间代码的影响保持最小(并且最小化异常淹没的可能性)。
Johnson 还列举了一个中间情形,对此他提出一个问题,“只是少数调用者希望处理问题吗?”对于这些情形,他也建议使用非检查型异常。作为该类别的一个例子,他列举了 JDO 异常 ?? 大多数情况下,JDO 异常表示的情况是调用者不希望处理的,但是在某些情况下,捕获和处理特定类型的异常是有用的。他建议在这里使用非检查型异常,而不是让其余的使用 JDO 的类通过捕获和重新抛出这些异常的形式来弥补这个可能性。
使用非检查型异常
关于是否使用非检查型异常的决定是复杂的,并且很显然没有明显的
答案。Sun 的建议是对于任何情况使用它们,而 C# 方法(也就是 Eckel 和其他人所赞同的)是对于任何情况都不使用它们。其他人说,“还存在一个中间情形。”
通过在 C++ 中使用异常,其中所有的异常都是非检查型的,我已经发现非检查型异常的最大风险之一就是它并没有按照检查型异常采用的方式那样自我文档化。除非 API 的创建者明确地文档化将要抛出的异常,否则调用者没有办法知道在他们的代码中将要捕获的异常是什么。不幸的是,我的经验是大多数 C++ API 的文档化非常差,并且即使文档化很好的 API 也缺乏关于从一个给定方法可能抛出的异常的足够信息。我看不出有任何理由可以说该问题对于 Java 类库不是同样的常见,因为 Jav 类库严重依赖于非检查型异常。依赖于您自己的或者您的合作伙伴的编程技巧是非常困难的;如果不得不依赖于某个人的文档化技巧,那么对于他的代码您可能得使用调用