Java 在外部API中使用检查异常是一个好主意吗?

Java 在外部API中使用检查异常是一个好主意吗?,java,exception-handling,Java,Exception Handling,在API中看到选中的预期并不罕见,最著名的例子之一是中的IOException。经常处理这种例外情况真的让我很恼火。更恼人的例子是在我们的一个项目中。它由几个组件组成,每个组件声明特定的检查异常。问题是(在我看来)在设计时并不确切知道某些异常会是什么。因此,例如,组件Configurator声明了ConfiguratorExeption。当我问为什么不使用未经检查的异常时,有人告诉我,我们希望我们的应用程序是健壮的,而不是在运行时崩溃。但这似乎是一个薄弱的论点,因为: 大多数异常都会导致应用程序

在API中看到选中的预期并不罕见,最著名的例子之一是中的
IOException
。经常处理这种例外情况真的让我很恼火。更恼人的例子是在我们的一个项目中。它由几个组件组成,每个组件声明特定的检查异常。问题是(在我看来)在设计时并不确切知道某些异常会是什么。因此,例如,组件
Configurator
声明了
ConfiguratorExeption
。当我问为什么不使用未经检查的异常时,有人告诉我,我们希望我们的应用程序是健壮的,而不是在运行时崩溃。但这似乎是一个薄弱的论点,因为:

  • 大多数异常都会导致应用程序无法使用。是的,它不会爆炸,但是它不能做任何事情,除了用消息淹没日志
  • 这些例外并不具体,实际上意味着“发生了不好的事情”。客户应该如何恢复
  • 事实上,所有的恢复都是通过记录异常然后吞咽它来完成的。这是在大型
    try-catch
    语句中执行的

  • 我认为,这是一种反复出现的模式。但仍然检查异常在API中被广泛使用。这是什么原因?是否有某些类型的API更适合于检查异常?

    检查异常应仅针对以下情况引发:1)异常异常它们是成功规则的例外,最糟糕的异常引发是防御性编码的可怕习惯;2)客户端可操作的异常。如果发生了API客户端无法以任何方式影响的情况,则将其作为RuntimeException。

    围绕此问题已经有很多讨论

    看看这篇关于这个主题的经典文章

    我个人倾向于使用<代码>运行时< /Cord>异常,并开始考虑使用检查异常在API中是一个坏主意。


    事实上,一些非常流行的Java API也开始做同样的事情,例如,Hibernate从版本3开始放弃了对运行时检查异常的使用,Spring框架也倾向于使用运行时而不是检查异常。

    大型库的一个问题是它们没有记录可能引发的所有异常,因此,如果一个未记录的运行时异常恰好是从您不“拥有”的深层代码中引发的,那么您的代码可能随时爆炸

    通过显式声明所有这些,至少使用所述库的开发人员可以让编译器帮助正确处理它们


    没有什么比凌晨3点做法医分析更能发现某些情况触发了这样一个未宣布的例外情况。

    对这件事有不同的看法,但我倾向于如下看法:

    • 检查异常表示在某些可预测的异常情况下可以合理预期会发生的事件,这些异常情况仍然“在程序/典型调用方的正常操作条件内”,并且通常可以在调用堆栈的不远处处理
    • 未检查的异常表示我们在程序的正常运行环境中“不会真正期望发生”的一种情况,可以在调用堆栈的较高位置处理(或者在使用更简单的应用程序时确实可能导致我们关闭应用程序)
    • enerror表示一种情况,如果出现这种情况,通常会导致我们关闭应用程序
    例如,在一个典型环境中,在某些异常情况下(但相当可预测),关闭文件可能会导致I/O错误(当磁盘已满时,在关闭时将缓冲区刷新到文件)。因此,让Closable抛出已检查IOException的决定可能是合理的

    另一方面,在标准JavaAPI中有一些示例,其中的决策不太可靠。我想说的是,当涉及到检查异常时,XMLAPI通常过于挑剔(为什么找不到一个XML解析器,这是您真正期望在典型应用程序中发生和处理的事情…?),反射API也是如此(你通常真的希望能找到类定义,而不管它们是不是…)但很多决定是有争议的

    一般来说,我同意“配置异常”类型的异常可能应该被取消选中

    请记住,如果您正在调用一个声明已检查异常的方法,但“真的不希望抛出该异常,而且真的不知道如果抛出该异常该怎么办”,那么您可以通过编程方式“耸耸肩”,并将其重新抛出到RuntimeException或错误…

    事实上,您可以使用该方法,以便生成一个通用异常(例如您的ConfiguratorException)可以提供有关出错原因的更多详细信息(例如FileNotFound)

    但是,一般来说,我会警告您不要这样做,因为这可能是一个错误(没有人应该关心您的配置程序是否试图通过网络或其他方式从文件系统、数据库中提取数据)


    如果您使用的是检查异常,那么至少您会知道您的抽象在哪里以及为什么会泄漏。嗯,这是一件好事。

    但是,例如,我怀疑
    close()上的
    IOException
    始终是客户可以操作的。根据我的经验,这通常是不可操作的。您向我表明了我的观点,这是Sun API的问题,而不是我的建议:-)这就是运行时异常的问题,您完全依赖于所有被记录的异常。是的,当一些未记录的运行时异常被抛出代码深处时,这是一件痛苦的事情。这些类型的异常可能很难测试