【问题标题】:Throwing generic Exception discouraged?不鼓励抛出通用异常?
【发布时间】:2011-12-19 01:20:59
【问题描述】:

为什么不鼓励抛出泛型 (java.lang.Exception) 异常,而通常足以处理方法中的大多数条件失败?我知道如果一个方法可以抛出多种类型的异常,那么抛出异常的特定子类可能会稍微澄清处理,但在一般的失败/成功情况下,我认为 Exception 服务绰绰有余。

【问题讨论】:

标签: java exception


【解决方案1】:

问题是Exception 也是RuntimeException 的超类,它包含一些不应被捕获的东西,因为它表明编程存在问题,而不是上下文引起的异常情况。在正常情况下,您不想捕获 BufferOverflowException 或 UnsupportedOperationException。此外,抛出单独的异常类型可以让调用代码控制如何处理每个异常类型。 Java 7 中通过新的多捕获功能减少了样板。

【讨论】:

  • 这是另一个重要问题,+1。
  • @MarkPeters 虽然我很少说“从不”,因为我认为即使是最糟糕的反模式在扭曲的情况下也可能是正确的答案,最好小心例外。有时它们必须由您没有编写的代码来处理,您最终会在整个商店中泄漏抽象。然后,当然,有些人会抓住Throwable,好像没什么大不了的:D
  • 诚实的问题,为什么抓到BufferOverflowException 或UnsupportedOperationException 是一件坏事?
  • @FRR UnsupportedOperationException 将指向编程错误,而不是预期的程序状态或可恢复问题。最好让它冒泡到任何选择处理它的地方。那是什么(以及它如何处理错误)取决于上下文。它可能导致程序终止、向用户发出错误通知或 500 内部服务器错误。当然,如果您有理由预测异常并且可以让代码做出明智的响应,那么您可以捕获它。只需避免在“正常”代码路径的流控制中转换异常处理即可。
  • 老实说,我忘记了为什么我不建议使用BufferOverflowException。据我所知,当时我没有使用 Java NIO。我实际上认为我打算以StackOverflowError 或IndexOutOfBoundsException 为例,只是感到困惑。 IndexOutOfBoundsException 会指出程序代码有问题(如UnsupportedOperationException),而StackOverflowError 可能会使程序处于不可预测的状态。
【解决方案2】:

如果您抛出更具体的异常,这不会阻止任何调用代码在一个Exception catch 块中处理所有这些异常。更具体的是更多地记录发生的错误类型,使程序员更容易单独处理它们。

此外,通过抛出“异常”本身,您基本上是在告诉代码调用者他们不能排除任何类别的异常。 IOException 可能会出现,NumberFormatException 也可能会出现,等等。

【讨论】:

    【解决方案3】:

    一如既往:视情况而定。

    我认为您向他人公开的 API 之间存在差异。这可能会持续一段时间。在这种情况下,您不知道调用者认为什么最适合他的情况。

    另一方面,总有一些代码仅供您自己在内部使用。抛出一个通用异常可能就足够了。但请记住,您可能希望稍后更改一些异常处理。当所有错误情况都被混合在一起时,这将更加困难。

    【讨论】:

      【解决方案4】:

      通常,您想知道您的应用程序中发生了什么,并且只捕获特定异常并让程序在您遇到您没有专门针对的异常时失败(或执行顺序更高)。 捕获异常会捕获所有异常,在某些情况下您不会知道您的程序失败了。

      【讨论】:

        【解决方案5】:

        GH 也一样。我会使用“空指针异常”和“内存不足异常”作为更明显的示例,说明您可能不会注意与真正的应用程序异常在同一块中捕获的异常类型。

        我还要补充一点,为未来的可扩展性付出一些努力是值得的。如果您到处抛出通用异常,然后您决定需要捕获一些异常而不是其他异常,那么返回并全部更改它们可能会很痛苦。但是,如果您只是在进行过程中创建所需的异常,那没什么大不了的。创建一个只接受带有消息的构造函数的新异常类需要 5 行代码?这是对未来的良好投资。

        就像编程中的许多事情一样,这是一个你能走多远的问题。我通常在我从事的几乎每个项目中创建一个相当通用的“BadInputException”,并在用户输入未通过验证标准时抛出它。然后我可以捕获 BadInputException 并将消息扔到屏幕上。如果我创建一个复杂的类,它会为不一致的数据和类似的事情抛出异常,我通常会为它创建一个异常类。就像我创建一个“TalkToDatabase”类一样,我将创建一个“TalkToDatabaseException”。 (如果有多种异常我知道我想捕获,但至少是一种。)

        顺便说一句,我不知道您是否正在考虑这一点,但我强烈反对检查错误消息的文本以确定错误类型。我见过他们到处抛出通用异常的程序,然后在 catch 块中他们有类似的代码

        // Very bad idea! Don't do this!
        catch (Exception ex)
        {
          if (ex.getMessage().equals("Invalid foo"))
          ... handle bad foo ...
          else if (ex.getMessage().equals("Plugh is over maximum"))
          ... handle bad plugh ...
          ... etc ...
        }
        

        最好为这些情况单独设置例外。不仅处理效率更高,而且假设您执行上述操作并且稍后有人出现并决定将消息更改为“Foo is invalid”?程序仍然可以编译,但不能正常工作。

        【讨论】:

          猜你喜欢
          • 2015-06-14
          • 1970-01-01
          • 1970-01-01
          • 2014-04-30
          • 1970-01-01
          • 2019-08-22
          • 1970-01-01
          • 2010-11-09
          • 2019-02-07
          相关资源
          最近更新 更多