我有一个像下面这样的课程:
public class MyClass {
public void foo() throws IOException {
System.out.println("Hola");
}
public MyClass() throws IOException {
}
}
如您所见,我在方法和构造函数的
IOException
子句中声明 throws
。但我不会在身体的任何地方抛出这个异常。所以它应该是一个编译时错误就像当我们尝试捕获不是从 try 块抛出的异常时。但在这种情况下它编译得很好。谁能解释一下这种行为背后的原因吗?
声明
throws IOException
并不要求您实际抛出异常。
如果是这样的话,那么就不可能编程,因为该方法的所有分支都需要抛出异常(即使在非异常情况下)。
这更多的是一个拥有完整合约的问题,其中调用者能够处理可能的异常。这适应了未来可能被迫实际抛出异常的实现。
可能出于同样的原因,允许重写的方法省略已检查的异常(您不会被迫抛出它)
Show Stopper 有一个很好的答案,并引用了一篇很棒的帖子。这个答案试图帮助 OP 了解什么是检查异常和未检查异常。
受检异常是签名中声明的异常(无论是否抛出)。
public void doSomething() throws SomeExtremelyDevastatingEndOfTheWorldException {
// Maybe it might happen (but whoever calls this MUST acknowledge handle this case)
}
该应用程序将无法编译,因为作者认为必须处理这种情况才能运行该应用程序。
未经检查的异常是不一定需要处理并且可以在运行时冒泡的异常。
public void doSomething() {
throws RuntimeException("not the end of the world...but we'll probably want this stacktrace and let the program run on");
}
现在,如果作者愿意,任何异常都可以成为未经检查的异常。
你是对的。这是该语言中的一个合法错误。我会给出一个原因。假设我正在编写一个
delete
方法,该方法应该删除文档。如果文档不存在,我想抛出异常(我不想默默地失败),所以我写了这个方法:
public void delete() throws DocumentNotFoundException
如果我忘记在文档不存在时抛出异常,则该错误将不会被捕获。正如你所说:
所以这应该是一个编译时错误,就像我们尝试捕获未从 try 块中抛出的异常一样。
如果声明抛出受检查异常但从未在方法中抛出,则正确的编译器行为是引发错误。这将帮助程序员捕获代码中的错误。
声明 throws IOException 并不要求该方法抛出异常。
它是方法签名的一部分,也是设计软件的一部分。考虑下面的例子。接口中有一种方法,并且有两种实现。无论是否抛出异常,两个实现都应该具有相同的签名。他们可以忽略例外条款。所以这就是编译器在编译时无法显示错误的正当原因。
Interface parent {
void method() throws Exception
}
Class Implementation1 {
void method() throws Exception {
System.out.println("Do not throws exception");
}
}
Class Implementation2 {
void method() throws Exception {
throw new Exception("Error");
}
}