Java 捕获异常并重新引用它,但它';这也不例外
我偶然发现这样的代码:Java 捕获异常并重新引用它,但它';这也不例外,java,exception,throws,Java,Exception,Throws,我偶然发现这样的代码: void run() { try { doSomething(); } catch (Exception ex) { System.out.println("Error: " + ex); throw ex; } } void doSomething() { throw new RuntimeException(); } 这段代码让我吃惊,因为它看起来像run()-方法能够抛出异常,因为它
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
这段代码让我吃惊,因为它看起来像run()
-方法能够抛出异常
,因为它捕获异常
,然后重新抛出它,但该方法没有声明抛出异常
,显然不需要。这段代码编译得很好(至少在Java11中)
我的期望是必须在run()
-方法中声明抛出异常
额外信息
以类似的方式,如果doSomething
被声明为抛出IOException
,则在run()
-方法中只需声明IOException
,即使捕获并重新调用了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语言规范中有什么允许run()
方法不需要在上面的代码片段中声明抛出异常
?(如果我想添加它,IntelliJ警告我,永远不会抛出异常)。我没有像你在问题中所问的那样扫描JLS
,因此请对这个答案持保留态度。我想对它发表评论,但它太大了
有时候我觉得很有趣,javac
在某些情况下(比如在您的情况下)是非常“聪明”的,但是将许多其他事情留给以后由JIT
处理。在这种情况下,只是编译器“能告诉”只有RuntimeException
会被捕获。这是显而易见的,这是你投入的唯一东西。如果您稍微将代码更改为:
void run() {
try {
doSomething();
} catch (Exception ex) {
Exception ex2 = new Exception();
System.out.println("Error: " + ex);
throw ex2;
}
}
您将看到一个不同的行为,因为现在javac
可以看出您正在抛出一个新的异常
,与您捕获的异常无关
但情况远非理想,您可以通过以下方式再次“欺骗”编译器:
void run() {
try {
doSomething();
} catch (Exception ex) {
Exception ex2 = new Exception();
ex2 = ex;
System.out.println("Error: " + ex);
throw ex2;
}
}
IMO,因为ex2=ex代码>它不应该再次失败,但它确实失败了
以防万一,这是用javac13+33
编译的。你在用什么编译器?如果是IDE编译器,那么请检查javac
——我遇到过Eclipse编译器更宽松的情况。我可以在openjdk-8上重现这种行为。值得注意的是,使用-source 1.6
标志编译时会产生预期的编译错误。使用source compatibility 7进行编译不会引发编译错误似乎编译器是从Java 7开始的,并且会对可能引发的实际异常进行更多检查。这个问题不是重复的,答案可以在Java SE 7及更高版本中我提供的详细链接中找到,当您在catch子句中声明一个或多个异常类型,并重试此catch块处理的异常时,编译器将验证重试异常的类型是否满足以下条件:1。1.试块可以把它扔出去。2.没有其他前面的catch块可以处理它。3.它是catch子句的异常参数之一的子类型或超类型。
绝对相关,但在IMO中没有提供足够详细的答案。答案的注释中有一个指向JLS的链接,除此之外,没有任何信息。我在一些链接中读到,有人提供,如果您在catch块中重新分配捕获的异常,那么编译器将无法智能化。我认为类似的情况也适用于这种情况。编译器知道将抛出ex2
异常,它最初创建为异常
,但随后被重新分配到ex
,因此编译器不可能聪明。@SimonForsberg对JLS
有热情的人可能会来提供所需的引用来证明这一点;不幸的是,我没有它们。对于记录,当我更改catch块以包含捕获的异常对自身的重新分配(ex=ex;
)时,启发式不再应用。这种行为似乎适用于从7到11的所有源级别,可能13请看一看问题,这也是一个重复的问题。这一个和可能的dup的dup解释了它,并链接到JLS。