使用 try-with-resources 语句可以完全防止异常屏蔽吗

Posted

技术标签:

【中文标题】使用 try-with-resources 语句可以完全防止异常屏蔽吗【英文标题】:Can exception masking be completely prevented with try-with-resources statement 【发布时间】:2018-11-05 05:56:17 【问题描述】:

我知道引入 try-with-resources 语句是为了解决(或)防止异常屏蔽。

考虑以下代码:

class TestExceptionSuppressing 
    public static void main(String[] args) 
        try 
            testMethod();
         catch (Exception e) 
            System.out.println(e.getMessage());
            for (Throwable t : e.getSuppressed()) 
                System.err.println("Suppressed Exceptions List: " + t);
            
        
    

    static void testMethod() 
        try (InnerClass inner = new InnerClass()) 
            throw new IOException("Exception thrown within try block");
         catch (Exception e) 
            throw new RuntimeException(
                    "Exception thrown within catch block.Hence exception thrown within try block will be lost (or) masked");
        
    

    static class InnerClass implements AutoCloseable 

        @Override
        public void close() throws Exception 
            throw new Exception("Exception thrown in close method will be tacked on to existing exceptions");
        
    

输出:在 catch 块中抛出异常。因此在 try 块中抛出的异常将丢失(或)被屏蔽

显然,testMethod() 的 catch 块中抛出的异常已经掩盖了 try 块中抛出的 io 异常以及被抑制并添加到此 io 异常中的异常(在 close 方法中抛出)

此代码示例可能证明 try-with-resources 可能无法完全防止异常屏蔽。

我知道这里的情况很混乱,可能会让人感到困惑,但有可能发生这种情况。 我的问题是,有没有办法防止这种情况发生,即即使使用 try-with-resources 语句仍然会发生异常屏蔽?

【问题讨论】:

这是与 try with resource 同时引入的更改,但是一个普通的 try/finally 块允许您查看被抑制的异常。 【参考方案1】:

使用RuntimeException(String, Throwable)可以保留原来的异常

使用指定的详细消息和原因构造一个新的运行时异常。

throw new RuntimeException(
                "Exception thrown within catch block  won't be lost (or) masked", e);

如果你想添加抑制的尝试和资源异常,你需要使用addSuppressed(Throwable)方法,在你的情况下:

RuntimeException runtimeException = new RuntimeException(
                    "Exception thrown within try block won't be lost (or) masked", e);
            runtimeException.addSuppressed(e.getSuppressed()[0]);

更多信息Suppressed Exceptions and Try With Resources

但是,仅仅因为 CloseException 在这种情况下被抑制,并不意味着这个被抑制的异常被忽略了。为了解决这种抑制异常的概念,Java 7 中的 java.lang.Throwable 类中添加了两个新方法和一个构造函数。

public final void addSuppressed(Throwable exception)

【讨论】:

这几乎也适用于所有异常,而不仅仅是 RuntimeException。稍后您可以使用 getCause() 检索包装的异常。 @Thilo 您通常是对的,但我看到(主要是自定义的)异常类型忘记添加它选项 @user7294900 - 你说在 try-with-resourced 语句的关联块中抛出的异常不会被这种方法掩盖。您指定的有关 catch 块中引发的异常的消息不会丢失。我认为这是一个拼写错误。不是吗?另外,我们是否也可以以这种方式指定已检查的异常,以使原始异常不丢失? @sake add to my answer 添加在 try-with-resourced 语句的关联块中引发的异常 @user7294900 - 我相信通过这种方法(即在构造一个 throwable 时提供原因并在 catch 块中为构造的 throwable 添加抑制的期望),我们可能会在 try 中得到(否则)被屏蔽的异常-with-reosurces 语句是 catch 块中异常的原因,但正如我在问题中提到的,异常屏蔽仍然可以通过 try-with-resources 语句发生,并且无法完全防止。你同意吗?

以上是关于使用 try-with-resources 语句可以完全防止异常屏蔽吗的主要内容,如果未能解决你的问题,请参考以下文章

java try-with-resource语句使用

在 JDK 9 中更简洁使用 try-with-resources 语句

使用 try-with-resources 语句可以完全防止异常屏蔽吗

我应该为每一行日志使用 try-with-resources 语句吗?

如何在 Java 中对接口对象使用 try-with-resources 语句

Java 7 使用TWR(Try-with-resources)完成文件copy