方法签名中的 Throw 和 Java 中的 Throw 语句之间的区别

2022-09-01 00:36:25

我试图弄清楚方法签名中的 Throw 和 Java 中的 Throw 语句之间的区别。抛入方法签名如下所示:

public void aMethod() throws IOException{
    FileReader f = new FileReader("notExist.txt");
}

抛出语句如下所示:

public void bMethod() {
    throw new IOException();
}

根据我的理解,in 方法签名是该方法可能引发此类异常的通知。 语句是在相应情况下实际抛出创建的对象。从这个意义上说,如果方法中存在 throw 语句,则应始终显示 throw in 方法签名。throwsthrow

但是,以下代码似乎并非如此。代码来自库。我的问题是为什么会发生这种情况?我是否理解了错误的概念?

这段代码是从java.util.linkedList复制的。@author 乔什·布洛赫

 /**
 * Returns the first element in this list.
 *
 * @return the first element in this list
 * @throws NoSuchElementException if this list is empty
 */
public E getFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

答案更新:

更新1:上面的代码是否与以下内容相同?

// as far as I know, it is the same as without throws
public E getFirst() throws NoSuchElementException {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

更新2:对于选中的异常。签名中是否需要包含“抛出”?是的。

// has to throw checked exception otherwise compile error
public String abc() throws IOException{
    throw new IOException();
}

答案 1

你几乎是对的。除了一件事,我稍后会提到。

throws 与名称和参数一样是方法 API 的一部分。客户端知道,如果他们调用该方法,他们需要处理该异常 - 通过简单地抛出它或通过捕获它并处理它(这实际上可能需要抛出另一个包装原始的异常)。throws 在编译时进行寻址。

throw 是让运行时知道发生了什么不好的事情的实际行为 - 我们担心的异常情况实际上已经发生了。因此,它需要在运行时进行处理。

但是,当你说“如果方法中存在 throw 语句,则应该始终显示 Throw in 方法签名”时,你并不完全正确。这通常是正确的,但并非总是如此。我还可以调用另一个在我的方法中引发异常的方法,如果我没有捕获它,我的方法需要丢弃它。在这种情况下,我没有显式抛出相同的异常。

最后一点是,当异常是已检查的异常时,只需在 throws 中声明异常 -- 这意味着它来自 RuntimeException 的 Exception 类层次结构的另一端。常见的检查异常是 IOException 和 SQLException。如果未自行处理已检查的异常,则必须在方法签名的 throws 部分中列出这些异常。任何子类化 RuntimeException 的东西-比如你的例子中的 NoSuchElementException,以及讨厌的 NullPointerException--都是一个未经检查的异常,不必被捕获或抛出或任何东西。

通常,对于可恢复的问题(客户端知道可能发生的情况,并且可以正常处理问题并继续前进),将已检查的异常用于灾难性问题(如无法连接到数据库)。使用已检查的异常。

如果您可以跳过所有AOP内容,那么这是有关如何有效使用已检查和未检查异常的精彩讨论。


答案 2

维迪亚为您的问题提供了很好的答案。

最重要的一句话是“最后一点是,当异常是已检查的异常时,您只需要在抛出中声明异常”

只是为了向您展示一个示例代码,这意味着什么。想象一下,我们想使用FileOutputStream来传递一些数据。该函数将如下所示:

public void saveSomeData() throws IOException {
  FileInputStream in = null;
  FileOutputStream out = null;

  try {
    in = new FileInputStream("input.txt");
    out = new FileOutputStream("output.txt");
    int c;

    while ((c = out.read() != -1) {
      in.write(c);
    }
  } catch (Exception e) {
    e.printStackTrace();
  } finally {
    // Close in
    if (in != null) {
      in.close(); // <-- If something bad happens here it will cause runtime error!
    }
    // Close out
    ...
  }
}

现在想象一下,如果你不提供抛出IOException,并且在final{}语句中发生了一些不好的事情 - 这会导致错误。