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

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

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

抛出语句如下:

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

根据我的理解,方法签名中的throws是该方法可能抛出此类exception的通知。 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 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 f = first; if (f == null) throw new NoSuchElementException(); return f.item; } 

更新2:检查exception。 签名中是否需要“抛出”? 是。

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

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

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

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

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

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

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

如果你能够通过所有AOP的东西, 这是一个很好的讨论如何有效地使用已检查和未经检查的exception。

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

最重要的一句是“最后一点是,当exception是一个经过检查的exception时,你只需要在throws中声明一个exception”

只是为了向您展示示例代码,这意味着什么。 想象一下,我们想使用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并且在最终{}语句中发生了一些不好的事情 - 它会导致错误。

RuntimeException不必在try-catch块中处理,因此它们不必被声明为抛出, NoSuchElementException是RuntimeException因为它扩展了它。

方法签名中的throw属性,正如您正确猜到的那样,是对编译器提示该方法引发必须由调用者捕获的exception的提示。 这种exception,即称为检查exception ,是调用者必须始终捕获或再次发送给其调用者的东西。 这是编译器级别的东西,签名指定方法能够抛出的exception:这在调用者中强制执行try-catch或重新调度,在方法内部的某处执行throw语句,是​​开发人员指定的约束关于方法行为的一些事情。

另一方面,其他exception,即未经检查运行时exceptionNoSucheElementException是一个示例)是您不必强制指定的exception,因为它们来自不同的情况。

概念上的区别在于,检查exception通常用于警告开发人员应以某种方式(想想IOException )处理的exception情况,而未选中则是真正的错误(如NullPointerException或类似于NoSuchElementException