研究以下方法:
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在这些情境中使用双重标准?
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 Files\Java\jdk1.7.0_45\bin>javac D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.java
D:\DNN-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.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-Project\DNN-Project\src\main\java\exceptionsAndAssertions\RethowTest.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
答案 0 :(得分:6)
可访问性规则在Java 8 JLS 14.21(和Java 7)中定义如下:
如果满足以下两个条件,则可以访问catch块C:
C的参数类型是未经检查的异常类型或Exception或Exception的超类,可以访问try块中的或某些表达式或throw语句,并且可以抛出类型可分配的已检查异常到C的参数类型。(如果包含它的最内层语句可以访问,则表达式是可到达的。)
表达式的正常和突然完成见§15.6。
try语句中没有先前的catch块A,因此C的参数类型与A参数类型的子类相同。
请注意,规则不得禁止您的示例代码。第二个捕获块不符合第二个要点的标准。
(在示例的原始版本中,您捕获了Exception
。可达性推理会有所不同,但答案是相同的 - 有效代码。)
这是不一致的吗?对于你的例子,你可以认为是这种情况。
为什么他们没有在可达性规则中解决这个问题?我不知道。你需要问Java设计师!!但是:
可达性规则的公式需要更加复杂才能解决这个问题。规范中的额外(不必要的)复杂性是一个问题。
你可以说这种不一致并没有破坏任何东西。可访问性规则实际上只是一种在用户代码中拾取潜在错误的方法。它不涉及类型安全或可预测的执行;即会破坏Java运行时语义的东西。
如果他们现在更改了规范,那么会使一小部分有效和有效的Java程序无效。鉴于稳定性是Java的主要卖点之一,这不是一个好主意。
另一方面,我无法想到他们无法解决规范中这种“不一致”的技术原因。
您注意到某些Java编译器会在第二个catch
上发出警告消息。那没问题。允许Java编译器为(技术上)合法的Java代码提供警告。
如果它们是错误,那么从技术上讲,这将是一个编译器错误...根据我对JLS的阅读。
答案 1 :(得分:1)
catch (Exception ...)
块将捕获运行时异常。它原则上永远不可达。
FileNotFoundException
是一个经过检查的例外。只有try块中的某些内容或其子类之一才能访问它的catch块。
[回应请求]
答案 2 :(得分:-3)
如果您实例new FileNotFoundException()
,则调用类FileNotFoundException
的构造函数。在这个构造函数中,通过调用本机方法fillInStackTrace
可以从理论上抛出IOException - 编译器可能不知道构造函数的内容是什么,可能会抛出IOException
。
请参阅此文章:示例中的https://community.oracle.com/thread/1445008?start=0。
如果编译器针对每个资源调查构造函数FileNotFoundException()
:它是一个忽略性能的开销java。