提问人:Simon Forsberg 提问时间:10/16/2019 最后编辑:Simon Forsberg 更新时间:10/4/2022 访问量:1780
捕获异常并重新抛出它,但它不是异常
Catching an Exception and rethrowing it, but it's not an Exception
问:
我偶然发现了如下所示的代码:
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
这段代码让我感到惊讶,因为看起来 -method 能够抛出一个 ,因为它捕获然后重新抛出它,但该方法没有被声明为抛出,显然不需要。这段代码编译得很好(至少在 Java 11 中是这样)。run()
Exception
Exception
Exception
我的期望是我必须在 -method 中声明。throws Exception
run()
额外信息
以类似的方式,如果被声明为抛出,那么只需要在 -方法中声明,即使被捕获并重新抛出。doSomething
IOException
IOException
run()
Exception
void run() throws IOException {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() throws IOException {
// ... whatever code you may want ...
}
问题
Java 通常喜欢清晰,这种行为背后的原因是什么?一直都是这样吗?Java 语言规范中哪些内容允许该方法不需要在上面的代码片段中声明?(如果我添加它,IntelliJ 会警告我永远不会抛出它)。run()
throws Exception
Exception
答:
我没有像你在问题中问的那样扫描过,所以请对这个答案持保留态度。我想把它作为一个评论,但它太大了。JLS
我有时觉得很有趣,在某些情况下(就像你的情况一样)非常“聪明”,但还有很多其他事情需要稍后处理。在这种情况下,只是编译器“可以告诉”只有 a 会被捕获。这很明显,这是你唯一投入的东西.如果您稍微将代码更改为:javac
JIT
RuntimeException
doSomething
void run() {
try {
doSomething();
} catch (Exception ex) {
Exception ex2 = new Exception();
System.out.println("Error: " + ex);
throw ex2;
}
}
你会看到一个不同的行为,因为现在可以看出你正在抛出一个新的,与你抓住的那个无关。javac
Exception
但事情远非理想,您可以通过以下方式再次“欺骗”编译器:
void run() {
try {
doSomething();
} catch (Exception ex) {
Exception ex2 = new Exception();
ex2 = ex;
System.out.println("Error: " + ex);
throw ex2;
}
}
IMO,因为它不应该再次失败,但它确实如此。ex2 = ex;
以防万一这是用javac 13+33
评论
ex2
Exception
ex
JLS
ex = ex;
如果未经检查的异常可以通过方法或构造函数的执行引发并在方法或构造函数边界之外传播,则不需要在方法或构造函数的 throws 子句中声明这些异常。RuntimeException 未选中。
评论
javac
-source 1.6
In detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions : 1. 1. The try block is able to throw it. 2. There are no other preceding catch blocks that can handle it. 3. It is a subtype or supertype of one of the catch clause's exception parameters.