我遇到了一个令人不安的情况,我希望Java(通过IllegalArgumentException
来自Throwable.addSuppressed
)抱怨两次抛出相同的异常,一次来自try-with-resources块,一次来自AutoCloseable
班的关闭()例程。我在下面创建了一个简单的测试用例,突出了问题。
我使用以下代码运行JDK 1.7.0_65:
public class TestDoubleThrow {
public static void main(String[] args) {
class TestA implements AutoCloseable {
RuntimeException e;
public TestA(RuntimeException e) { this.e = e; }
@Override public void close() { throw e; }
}
RuntimeException e = new RuntimeException("My Exception");
try (TestA A = new TestA(e)) {
throw e;
}
}
}
当我通过命令行编译并运行上面的代码时,我得到了预期的结果,这个错误表明我试图自我抑制和异常:
[coreys terminal]$ java TestDoubleThrow.java ; java TestDoubleThrow
Exception in thread "main" java.lang.IllegalArgumentException: Self-suppression not permitted
at java.lang.Throwable.addSuppressed(Throwable.java:1043)
at TestDoubleThrow.main(TestDoubleThrow.java:12)
Caused by: java.lang.RuntimeException: My Exception
at TestDoubleThrow.main(TestDoubleThrow.java:9)
但是,当我从Eclipse构建并运行相同的代码时,我得不到相同的结果,我得到以下内容:
Exception in thread "main" java.lang.RuntimeException: My Exception
at TestDoubleThrow.main(TestDoubleThrow.java:9)
我从命令行构建后删除了.class路径,以确保Eclipse重建它。从调试器运行我注意到,从Eclipse开始,代码永远不会进入java.lang.Throwable.addSuppressed()
。
有趣的是,如果我从Eclipse构建类,那么从命令行运行它我不会看到自我抑制错误。类似地,如果我从命令行构建类并从Eclipse运行它(无需从Eclipse构建),那么我会看到错误。这表明eclipse如何构建课程是有趣的。
我想知道如何确保Eclipse能够以这样的方式构建类,以便我得到错误,因为出于我的目的,这是一个错误,我希望能够在构建和运行时检测到它蚀。
答案 0 :(得分:3)
Eclipse拥有自己的编译器并生成不同的输出。 Eclipse编译的代码在调用Throwable.addSuppressed之前检查被抑制的异常是否等于自身。您可以使用 javap 工具查看此内容。
请参阅Eclipse编译器输出中的if_acmpeq
行。
JDK行为更紧密地遵循the example in the specification。您可以raise a defect与Eclipse团队合作。
JDK / javac输出:
public static void main(java.lang.String[]);
Code:
0: new #2 // class java/lang/RuntimeException
3: dup
4: ldc #3 // String My Exception
6: invokespecial #4 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
9: astore_1
10: new #5 // class TestDoubleThrow$1TestA
13: dup
14: aload_1
15: invokespecial #6 // Method TestDoubleThrow$1TestA."<init>":(Ljava/lang/RuntimeException;)V
18: astore_2
19: aconst_null
20: astore_3
21: aload_1
22: athrow
23: astore 4
25: aload 4
27: astore_3
28: aload 4
30: athrow
31: astore 5
33: aload_2
34: ifnull 63
37: aload_3
38: ifnull 59
41: aload_2
42: invokevirtual #8 // Method TestDoubleThrow$1TestA.close:()V
45: goto 63
48: astore 6
50: aload_3
51: aload 6
53: invokevirtual #9 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
56: goto 63
59: aload_2
60: invokevirtual #8 // Method TestDoubleThrow$1TestA.close:()V
63: aload 5
65: athrow
Exception table:
from to target type
21 23 23 Class java/lang/Throwable
41 45 48 Class java/lang/Throwable
21 33 31 any
Eclipse输出:
public static void main(java.lang.String[]);
Code:
0: new #16 // class java/lang/RuntimeException
3: dup
4: ldc #18 // String My Exception
6: invokespecial #20 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
9: astore_1
10: aconst_null
11: astore_2
12: aconst_null
13: astore_3
14: new #23 // class TestDoubleThrow$1TestA
17: dup
18: aload_1
19: invokespecial #25 // Method TestDoubleThrow$1TestA."<init>":(Ljava/lang/RuntimeException;)V
22: astore 4
24: aload_1
25: athrow
26: astore_2
27: aload 4
29: ifnull 37
32: aload 4
34: invokevirtual #28 // Method TestDoubleThrow$1TestA.close:()V
37: aload_2
38: athrow
39: astore_3
40: aload_2
41: ifnonnull 49
44: aload_3
45: astore_2
46: goto 59
49: aload_2
50: aload_3
51: if_acmpeq 59
54: aload_2
55: aload_3
56: invokevirtual #31 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
59: aload_2
60: athrow
Exception table:
from to target type
24 26 26 any
14 39 39 any
我使用的是JDK 8和Eclipse 4.4。