【问题标题】:Exception self suppression error in try-with-resources not occuring from EclipseEclipse 中未发生 try-with-resources 中的异常自我抑制错误
【发布时间】:2014-10-25 05:38:33
【问题描述】:

我遇到了一个令人不安的情况,我希望 Java 会抱怨(通过来自 Throwable.addSuppressedIllegalArgumentException)两次抛出相同的异常,一次来自 try-with-resources 块,一次来自 @987654323 @ 类的 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 可以以我确实收到错误的方式构建类,因为就我的目的而言,这是一个错误,我希望能够在我构建和运行时检测到它日食。

【问题讨论】:

    标签: java eclipse suppression


    【解决方案1】:

    Eclipse 有它自己的编译器并产生不同的输出。 Eclipse 编译的代码在调用Throwable.addSuppressed 之前检查抑制的异常是否等于自身。您可以使用 javap 工具查看此内容。

    查看 Eclipse 编译器输出中的 if_acmpeq 行。

    JDK 行为更接近于the example in the specification。您可以与 Eclipse 团队一起raise a defect

    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。

    【讨论】:

    • 在两种情况下查看字节码时,我注意到了类似的事情。我发现以JDK bug here 讨论的错误。无论是 JDK 错误还是 Eclipse 错误,我都不能说 :) 在两者之间保持一致的行为会很好,事实上 Eclipse 实际上插入的代码会绕过 Throwable 中的代码。
    猜你喜欢
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 2022-09-27
    • 2014-01-06
    • 2017-03-15
    相关资源
    最近更新 更多