我遇到了一个麻烦的情况,我希望Java(通过Throwable.addSuppressed
的IllegalArgumentException
)抱怨两次抛出相同的异常,一次是在try-with-resources块中,另一次是从AutoCloseable
类的close()例程中。我在下面创建了一个简单的测试用例,突出了这个问题。
我运行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能够以我确实收到错误的方式构建类,因为就我而言,这是一个错误,我希望在从Eclipse构建和运行时能够检测到它。
Eclipse有自己的编译器,并产生不同的输出。Eclipse编译的代码在调用Throwable.addSuppressed之前检查被抑制的异常是否等于自身。您可以使用javap工具看到这一点。
请参阅Eclipse编译器输出中的if_acmpeq
行。
JDK的行为更加符合规范中的示例。您可以向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。