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

When should we use throws keyword in Java?

throws 关键字仅用于检查异常。它指示调用者使用 try catch 块通过 throws 关键字排除所有列出的异常。

既然我们知道我们的模块可能会出现什么样的检查异常,那么:

  1. 为什么我们不使用模块内部的try catch 块来处理已检查的异常?
  2. 我们可以使用 try-catch 块处理模块内部的检查异常吗?
  3. 如果 (2) 的答案是肯定的,那么为什么我们要强制调用者使用 throws 关键字排除那些异常,而我们可以在模块本身内部排除相同的异常?

这样就不用每次调用方法时都手动排除异常

有时您想在应用程序的另一部分管理一些异常。

例如,您可以拥有一个只向互联网发送请求并带回响应的包。 如果您在无外设服务器应用程序和具有用户界面的桌面应用程序中将此包用作 lib,则您需要以不同方式管理 to 异常。记录它并重试无头应用程序并显示错误消息和桌面应用程序的重试按钮。

如果你只在 net 包管理异常,你不能有这个,如果你抛出异常,应用程序的其余部分可以随意处理。

这里还有其他用例,如果您不知道您的包将如何使用(这样您或其他人可以选择稍后如何处理),这可能很有用

总体思路是分离纯代码逻辑和异常管理。

  1. 都是关于如何从异常中恢复的。什么应该例如java.lang.File文件不存在时怎么办?因为它不知道什么对被叫方最好,所以它让被叫方处理这种情况
  2. 当然你可以在你的模块中处理异常,如果它清楚应该如何处理所述异常。如果处理依赖于被调用者或上下文,让调用函数决定
  3. 现在应该清楚了

我以FileInputStream::new抛出FileNotFoundException为例来澄清大家的误解。

例如我们有这样的代码:

FileInputStream fis = new FileInputStream("/some/path/to/file.txt");

那可能会抛出一个 FileNotFoundException,而你是说,

FileInputStream obviously knows that it is going to throw a FileNotFoundException, so why does it not handle it itself?

因为FileInputStream不知道如何处理异常!

根据情况,有很多方法可以处理 FileNotFoundException:

  • 如果文件路径来自用户输入,您可能会要求用户输入另一个文件路径
  • 您可能会显示一条错误消息
  • 你可能什么都不做,让它崩溃

根据情况,以上所有都是完全明智的选择。 FileInputStream 怎么会知道你的情况?不是!

这就是为什么它用 throws 子句说:

I'm throwing these exceptions, handle it yourself.

请注意,您也可以 re-throw 例外。在许多情况下,将错误传递给下一层是完全合理的。如果您还向方法添加 throws IOException ,则它不必处理它。在许多情况下,处理此类故障的唯一方法就是失败,而这通常应该在最外层完成。

IDEs 会提醒您缺少 throws 并建议解决此问题的可能方法。因此,与定义失败行为的好处相比,开发人员的工作量非常轻。

然而应该清楚的是,IDE 不是编译器可以预测未来,或者适当的抽象。

首先,接口或抽象方法可以——也应该——声明异常。例如:

interface Opener {
    InputStream open(String id) throws IOException;
}

提醒该接口用户处理此类错误,例如文件未找到异常。

此外,编译器或 IDE 不知道正确的抽象。您的代码可能会执行

if (httpcode == 404)
  throw new FileNotFoundException("Server returned a 404 error.");

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