如果我使用多个catch块,为什么java不检测不可达的catch块?
研究以下方法:
static private void foo() {
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
尽管最后的catch块实际上无法访问,但此代码编译良好。
现在让我们来评论throw new FileNotFoundException();
行
执行:
哎呀! 我们看
Unreachable catch block for FileNotFoundException. This exception is never thrown from the try statement body
奇怪。 为什么java为这些情况使用双重标准?
@Peter Rader更新
static private void foo(FileNotFoundException f) {
try {
throw f;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
工作以及构造函数调用
更新
我注意到,在不同版本的java编译器中,我看到编译此代码的不同结果。
public class RethowTest {
public static void main(String[] args) {
try {
throw new FileNotFoundException();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
throw e;
}
}
}
在我的本地电脑上:java 1.7.0_45 -
C:Program FilesJavajdk1.7.0_45bin>javac D:DNN-ProjectDNN-ProjectsrcmainjavaexceptionsAndAssertionsRethowTest.java
D:DNN-ProjectDNN-ProjectsrcmainjavaexceptionsAndAssertionsRethowTest.java:15: warning: unreachable catch clause
} catch (IOException e) {
^
thrown type FileNotFoundException has already been caught
1 warning
java 1.6.0_38
D:DNN-ProjectDNN-ProjectsrcmainjavaexceptionsAndAssertionsRethowTest.java:16: unreported exception java.io.IOException; must be caught or declared to be thrown
throw e;
^
1 error
http://www.compileonline.com/compile_java_online.php(Javac 1.7.0_09) -
HelloWorld.java:9: warning: unreachable catch clause
} catch (IOException e) {
^
thrown type FileNotFoundException has already been caught
1 warning
可达性规则在Java 8 JLS 14.21(和Java 7)中定义如下:
如果满足以下两个条件,则catch块C可到达:
C的参数类型是未检查的异常类型或Exception或Exception的超类, 或者try块中的某个表达式或throw语句是可访问的,并且可以抛出一个检查的异常,该异常的类型可分配给C的参数类型。 (如果包含它的最内层语句可以访问,则表达式是可访问的。)
表达式的正常和突然完成见§15.6。
在try语句中没有早先的catch块A,使得C的参数类型与A的参数类型相同或是其类型的子类。
请注意,规则不禁止您的示例代码。 第二个catch块不符合第二个项目符号的标准。
(在该示例的原始版本中,您捕获了Exception
。可达性推理会有所不同,但答案是相同的 - 有效的代码。)
这是否不一致? 对于你的例子,你可能会认为是这样。
他们为什么没有在可达性规则中解决这个问题? 我不知道。 你需要问Java设计师! 然而:
可达性规则的制定将需要显着更复杂来处理这个问题。 规范中额外(不必要的)复杂性是一个问题。
你可能会认为这种不一致并没有破坏任何东西。 可达性规则实际上只是一种挑选用户代码中潜在错误的方法。 它不涉及类型安全或可预测的执行; 即会“破坏”Java运行时语义的东西。
如果他们现在改变了规范,那么会导致一小部分有效和正在运行的Java程序失效。 这不是一个好主意,因为稳定性是Java的主要卖点之一。
另一方面,我想不出他们为什么不能解决规范中的这种“不一致性”的技术原因。
您注意到一些Java编译器在第二个catch
上给出了警告消息。 那没问题。 Java编译器允许为(技术上)合法的Java代码提供警告。
如果他们是错误的,那在技术上会是一个编译器错误......根据我对JLS的阅读。
catch (Exception ...)
块会捕获运行时异常。 原则上永远不可能达到。
FileNotFoundException
是一个检查的异常。 如果try块中的某个内容抛出它或其子类之一,那么它的catch块才是可访问的。
[回应请求]
如果实例化new FileNotFoundException()
,则调用Class FileNotFoundException
的构造FileNotFoundException
。 在这个构造函数中,可以通过调用本地方法fillInStackTrace
来抛出IOException - 编译器可能不知道构造函数的内容是什么,可能会抛出IOException
。
请参阅此文章:https://community.oracle.com/thread/1445008?start=0例如。
如果编译器查看每个occourcence的构造函数FileNotFoundException()
:它的开销java忽略了性能。
上一篇: Why does not java detect unreachable catch block if I use multiple catch blocks?