【问题标题】:Is there an advantage to declaring that a method throws an unchecked exception?声明一个方法抛出一个未经检查的异常有好处吗?
【发布时间】:2014-07-03 12:44:34
【问题描述】:

如果我有一个抛出未经检查的异常的方法,例如:

void doSomething(int i) {
  if (i < 0) throw new IllegalArgumentException("Too small");
  // ...
}

显式声明该方法抛出异常有什么好处,即

void doSomething(int i) throws IllegalArgumentException {
  if (i < 0) throw new IllegalArgumentException("Too small");
  // ...
}

与描述 javadoc 中的行为相反(或除此之外):

/**
 * This method does something useful.
 * @param i some input value
 * @throws IllegalArgumentException if {@code i < 0}
 */
void doSomething(int i) {
  if (i < 0) throw new IllegalArgumentException("Too small");
  // ...
}

我声称拥有throws 没有用的原因是:

  • throws 没有提供关于在什么情况下抛出异常的信息,只是可能抛出异常;
  • 因为它是一个未经检查的异常,所以我在调用代码时不必强制处理异常。去看看doSomething的实现,我才真正知道可能会被抛出;
  • doSomething 的主体可能会调用引发其他类型未检查异常的代码;声称“此方法抛出IllegalArgumentException”似乎只是讲述了故事的一部分,可能;
  • 如果方法不是最终的,则可以重写它,以便声明新的实现以抛出额外的未经检查的异常;你不知道你在调用哪个实现。

我声称拥有throws 会很有用的原因是:

  • 它报告了一个您在调用该方法时可能会遇到的问题。

简而言之,我认为throws 是不必要的,但是通过@throws 的javadoc 描述很有用。我很想知道其他人对此的看法。

【问题讨论】:

标签: java exception unchecked-exception


【解决方案1】:

如果您的 API 用户看不到您的源代码,他将看不到 javadoc cmets。这就是为什么声明throws 子句可能有用的原因。

对于一些程序员来说,从方法签名中快速确定异常比查看 javadoc 中的内容更容易。

但总的来说,我认为仅在 javadocs 中列出未经检查的异常会更有用,因为如果在 throws 子句中同时存在已检查和未经检查的异常,情况可能会令人困惑。如果没有编译器或不查看每个异常类签名,您将无法确定异常的类型。

然而,未经检查的异常意味着情况很严重,程序在运行时无法修复。如果您出于检查异常的目的使用未经检查的异常(您假设情况可以修复)但由于某种原因您不希望编译器强制捕获异常,那么我建议也将异常放在 throws 子句中。

【讨论】:

  • 您提出了一个合理的观点,但它只有助于了解直接在我的方法中抛出的异常 - 假设 doSomething 调用一个抛出 NullPointerException 的方法。有两种情况:1)他们声明方法throws NullPointerException - 我应该声明我的方法也抛出该异常类型吗?我应该声明我可以在被调用代码中抛出所有传递抛出的未检查异常吗? 2) 如果他们没有声明throws NPE 方法,我可以知道它会在不访问他们的代码的情况下抛出 NPE 吗?
  • 1) 如果您认为您的 NPE 不是危急情况,即它是您的业务逻辑的一部分(我不推荐这种行为) - 请将其包含在 throws 2) 否你不能
  • 我认为,如果您打算在没有相关文档的情况下使用 API,那么无论如何您都是在走危险的路线。我只支持 Javadoc 指示。
【解决方案2】:

当你声明一个方法 throws 是一个异常时,你是在对调用者说:

你有两个选择:

  1. 重新声明自己抛出了同样的异常。
  2. 捕捉异常并处理。

在情况 1 中,它可能会提醒用户实现 finally - 这可能是一个奖励。

在情况 2 中,它将注意力集中在例外上,这也可能是一种奖励。

如果您隐藏了这种可能性,则用户不会收到上述提醒。

对我来说,一个人可能会不必要地弄乱他们的代码,而另一个人则保持它的甜美和简单。但是,一种方法鼓励您关注潜在问题,而另一种方法可能会让您感到幸福无知。

底线 - 问问自己,将异常声明为抛出会有多烦人(例如,您是否应该声明 throws NullPointerException? - 不!)并且这种刺激是否与将用户注意力集中在 catch 的好处相平衡, finallythrows

【讨论】:

    【解决方案3】:

    异常用于报告 3 种问题:

    • JVM 和低级运行时环境存在问题。
    • 检测到逻辑错误(错误)。
    • 程序员在尝试操作之前无法预测的运行时问题。

    前两种可能随时发生,基本上没有好的方法来处理它们。所以捕捉它们是没有意义的,因此通过在throws 子句中声明它们来记录它们是没有意义的。第三种是您希望客户了解和处理的类型。对于那些,您希望清楚地记录可能会引发异常,这意味着调用代码必须准备好通过捕获或正确传播异常来处理异常。您可以使用throws 子句来做到这一点。

    现在,在我看来,Java 语言设计者显然打算将受检异常,并且仅将受检异常用于第三种类型。如果总是这样,那么对您的问题的简单回答是,不,不要在 throws 子句中声明未经检查的异常。

    但是有一个并发症。 now quite common(Spring 普及)避免了第三种类型的检查异常,并在几乎所有情况下都使用未经检查的异常。如果您使用这种风格进行编程,使用throws 子句声明未经检查的异常可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-20
      • 2011-04-23
      • 1970-01-01
      • 2011-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多