方法签名中的抛出与Java中的抛出语句之间的区别

Wei*_*eng 33 java throw throws

我试图弄清楚方法签名中的Throws和Java中的Throw Statements之间的区别.方法签名中的引发如下:

public void aMethod() throws IOException{
    FileReader f = new FileReader("notExist.txt");
}
Run Code Online (Sandbox Code Playgroud)

抛出语句如下:

public void bMethod() {
    throw new IOException();
}
Run Code Online (Sandbox Code Playgroud)

根据我的理解,throwsin方法签名是一种通知,该方法可能会抛出这样的异常.throw语句是在相应的情况下实际抛出创建的对象.从这个意义上讲,如果方法中存在throw语句,则应始终显示方法签名中的throws.

但是,以下代码似乎没有这样做.代码来自库.我的问题是它为什么会发生?我理解错误的概念吗?

这段代码是java.util.linkedList的副本.@author Josh Bloch

 /**
 * 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;
}
Run Code Online (Sandbox Code Playgroud)

答案更新:

更新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;
}
Run Code Online (Sandbox Code Playgroud)

更新2:检查异常.我需要在签名中"抛出"吗?是.

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

Vid*_*dya 30

你非常正确.除了一件事我会稍微提一下.

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

throw是让运行时知道发生了不好事情的实际行为 - 我们担心的特殊情况实际上已经发生了.所以它需要在运行时处理.

但是当你说"如果方法中存在一个throw语句时,应该总是出现方法签名时,你就不太对了." 这通常是正确的,但并非总是如此.我还可以调用另一个在我的方法中抛出异常的方法,如果我没有捕获它,我的方法需要抛出它.在这种情况下,我没有明确抛出同一个异常.

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

通常,您使用已检查的异常来解决可恢复的问题(客户端知道会发生什么,可以优雅地处理问题并继续前进)和未经检查的灾难性异常(例如无法连接到数据库).

如果您可以通过所有AOP的内容,是一个很好的讨论如何有效地使用已检查和未检查的异常.


0le*_*leg 5

Vidya为您的问题提供了很好的答案.

最重要的一句话是"最后一点是,当异常是一个经过检查的异常时,你只需要在throws中声明一个异常"

只是为了向您展示示例代码,这意味着什么.想象一下,我们想使用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
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

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