使用 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 语句可以完全防止异常屏蔽吗的主要内容,如果未能解决你的问题,请参考以下文章
在 JDK 9 中更简洁使用 try-with-resources 语句
使用 try-with-resources 语句可以完全防止异常屏蔽吗
我应该为每一行日志使用 try-with-resources 语句吗?