13

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

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是不必要的,但是通过 javadoc 描述@throws很有用。我很想知道其他人对此的看法。

4

3 回答 3

6

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

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

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

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

于 2014-07-03T12:49:47.507 回答
4

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

你有两个选择:

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

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

在案例 2 中,它将注意力集中在异常上,这也可能是一种奖励。

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

对我来说,一个人可能会不必要地弄乱他们的代码,而另一个人则保持它的甜美和简单。然而,一种鼓励关注潜在的问题,而另一种可能会让你陷入幸福的无知之中。

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

于 2014-07-03T14:39:19.150 回答
0

异常用于报告 3 种问题:

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

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

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

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

于 2017-11-22T23:39:09.727 回答