在Java中什么时候应该使用throws关键字?

6

throws关键字仅用于检查异常。它指示调用者使用try-catch块来捕获由throws关键字列出的所有异常。

既然我们知道在我们的模块中可能会发生什么类型的检查异常,那么:

  1. 为什么我们不在模块内部使用try-catch块来处理检查异常?
  2. 我们能否在模块内部使用try-catch块来处理检查异常?
  3. 如果问题(2)的答案是YES,则为什么我们强制调用者使用throws关键字来捕获这些异常,而不是在模块内部捕获相同的异常?

这样我们就不必每次调用该方法时手动捕获异常。


1
"throws关键字仅用于已检查异常" - 请注意,您也可以将其用于未检查的异常,以防您不知道。 - Zabuzard
2
一个方法并不总能决定对于异常情况应该采取的最佳反应方式。这时候就是你的方法的用户定义错误处理的时候了。想象一下有一个 openFile 方法,但文件不存在。openFile 方法无法解决这个问题,必须由用户来解决。 - Zabuzard
4个回答

5
  1. 这是关于如何从异常中恢复的问题。例如,当java.lang.File文件不存在时,该怎么办?由于它不知道对调用者来说什么是最好的,所以它让调用者处理此情况。
  2. 当然,如果清楚了如何处理这些异常,您可以在模块中处理它们。如果处理取决于被调用方或上下文,请让调用函数决定。
  3. 现在应该很清楚了。

5
让我以FileInputStream::new抛出FileNotFoundException为例,为您澄清误解。所以,例如我们有如下代码:
FileInputStream fis = new FileInputStream("/some/path/to/file.txt");

这可能会抛出一个FileNotFoundException,你正在说,

FileInputStream显然知道它要抛出FileNotFoundException,为什么它不自己处理呢?

因为FileInputStream不知道如何处理异常!
根据情况,有很多种方法可以处理FileNotFoundException
  • 如果文件路径来自用户输入,则可以要求用户输入另一个文件路径
  • 您可以显示错误消息
  • 您可能什么也不做,让它崩溃
以上所有选项都可能是完全合理的选项,具体取决于情况。FileInputStream怎么会了解你的情况呢?它不会!
这就是为什么它带着throws子句说:

我正在抛出这些异常,请自行处理。


1
有时候你想在应用程序的另一部分管理一些异常。
例如,你可以有一个仅向互联网发送请求并获取响应的包。如果你将这个包作为库在无头服务器应用和带用户界面的桌面应用中使用,你会希望以不同的方式管理异常。对于无头应用,记录并重试,对于桌面应用,则显示错误消息和重试按钮。
如果你只在网络包中管理异常,就无法做到这一点。如果抛出异常,则应用程序的其余部分可以根据你的意愿处理它。
还有其他用例可以派上用场,如果你不知道如何使用你的包(因此你或其他人可以随后选择如何处理)。
总的思路是解耦纯代码逻辑和异常管理。

1
请注意,您也可以重新抛出异常。在许多情况下,将错误传递给下一层是完全合理的。如果您还将throws IOException添加到方法中,则无需处理它。在许多情况下,处理此类故障的唯一方法是失败,并且通常应在最外层执行。
IDE会提醒您缺少throws并建议可能的解决方法。因此,与定义失败行为相比,开发人员的工作量非常小。
但是,应清楚地了解,IDE而不是编译器可以预测未来或正确的抽象。
首先,接口或抽象方法可以声明异常。例如:
interface Opener {
    InputStream open(String id) throws IOException;
}

提醒用户处理此界面的错误,例如文件未找到异常。
此外,编译器或IDE不知道正确的抽象。您的代码可能会进行一些操作。
if (httpcode == 404)
  throw new FileNotFoundException("Server returned a 404 error.");

但是你现在还不确定是否稍后会将其更改为不同的异常,因为它实际上不是文件。例如,您可能希望有一个网络异常的子类。但是,您可以确定您打算抛出的所有异常都将是 IOException,因此需要该方法的用户在此级别上处理它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接