sp;JNDI 装载资源的方法在不能找到资源时,应该抛出某种 ResourceNotFound 异常(通常使用异常链来保存隐含的原因),而不是更底层的 IOException、SQLException 或者 NamingException。
重新考察非检查型异常的正统观点
最近,几位受尊敬的专家,包括 Bruce Eckel 和 Rod Johnson,已经公开声明尽管他们最初完全同意检查型异常的正统观点,但是他们已经认定排他性使用检查型异常的想法并没有最初看起来那样好,并且对于许多大型项目,检查型异常已经成为一个重要的问题来源。Eckel 提出了一个更为极端的观点,建议所有的异常应该是非检查型的;Johnson 的观点要保守一些,但是仍然暗示传统的优先选择检查型异常是过分的。(值得一提的是,C# 的设计师在语言设计中选择忽略检查型异常,使得所有异常都是非检查型的,因而几乎可以肯定他们具有丰富的 Java 技术使用经验。但是,后来他们的确为检查型异常的实现留出了空间。)
对于检查型异常的一些批评
Eckel 和 Johnson 都指出了一个关于检查型异常的相似的问题清单;一些是检查型异常的内在属性,一些是检查型异常在 Java 语言中的特定实现的属性,还有一些只是简单的观察,主要是关于检查型异常的广泛的错误使用是如何变为一个严重的问题,从而导致该机制可能需要被重新考虑。
检查型异常不适当地暴露实现细节
您已经有多少次看见(或者编写)一个抛出 SQLException 或者 IOException 的方法,即使它看起来与数据库或者文件毫无关系呢?对于开发人员来说,在一个方法的最初实现中总结出可能抛出的所有异常并且将它们增加到方法的 throws 子句(许多 IDE 甚至帮助您执行该任务)是十分常见的。这种直接方法的一个问题是它违反了 Bloch 的 第 43 条 ?? 被抛出的异常所位于的抽象层次与抛出它们的方法不一致。
一个用于装载用户概要的方法,在找不到用户时应该抛出 NoSuchUserException,而不是 SQLException ?? 调用者可以很好地预料到用户可能找不到,但是不知道如何处理 SQLException。异常链可以用于抛出一个更为合适的异常而不用丢弃关于底层失败的细节(例如栈跟踪),允许抽象层将位于它们之上的分层同位于它们之下的分层的细节隔离开来,同时保留对于调试可能有用的信息。
据说,诸如 JDBC 包的设计采取这样一种方式,使得它难以避免该问题。在 JDBC 接口中的每个方法都抛出 SQLException,但是在访问一个数据库的过程中可能会经历多种不同类型的问题,并且不同的方法可能易受不同错误模式的影响。一个 SQLException 可能指示一个系统级问题(不能连接到数据库)、逻辑问题(在结果集中没有更多的行)或者特定数据的问题(您刚才试图插入行的主键已经存在或者违反实体完整性约束)。如果没有犯不可原谅的尝试分析消息正文的过失,调用者是不可能区分这些不同类型的 SQLException 的。(SQLException 的确支持用于获取数据库特定错误代码和 SQL 状态变量的方法,但是在实践中这些很少用于区分不同的数据库错误条件。)
不稳定的方法签名
不稳定的方法签名问题是与前面的问题相关的 ?? 如果您只是通过一个方法传递异常,那么您不得不在每次改变方法的实现时改变它的方法签名,以及改变调用该方法的所有代码。一旦类已经被部署到产品中,管理这些脆弱的方法签名就变成一个昂贵的任务。然而,该问题本质上是没有遵循 Bloch 提出的第 43 条的另一个症状。方法