try-with-resources前世今生

tech2026-02-27  2

try-with-resources

try-with-resources是1.7新加入的语法糖。 针对一些流资源的关闭。只要流资源实现了AutoCloseable接口,就可以通过try-with-resources模式进行自动关闭。

异常屏蔽现象

一个方法只能抛出一个异常,但finally语句块即使在try块出现异常时也会执行,导致finally块中异常将try块中异常覆盖。如:

@Test public void test() throws Exception { Connection conn = null; try { conn = new Connection(); conn.sendData(); } finally { if (conn != null) { conn.close(); } } } class Connection implements AutoCloseable { public void sendData() throws Exception { throw new Exception("send data"); } @Override public void close() throws Exception { throw new Exception("close"); } } java.lang.Exception: close at common.TryWithResource$Connection.close(TryWithResource.java:27) at common.TryWithResource.main(TryWithResource.java:15)

这样的日志我们无法知道是sendData抛出了异常还是close抛出了异常。 在上面的场景中,我们更希望同时看到这两个异常。

addSuppressed()方法

jdk1.7新增了addSuppressed()方法,用来解决合并多个异常信息

private static final List<Throwable> SUPPRESSED_SENTINEL = Collections.unmodifiableList(new ArrayList<Throwable>(0)); private List<Throwable> suppressedExceptions = SUPPRESSED_SENTINEL; public final synchronized void addSuppressed(Throwable exception) { if (exception == this) throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE, exception); if (exception == null) throw new NullPointerException(NULL_CAUSE_MESSAGE); if (suppressedExceptions == null) // Suppressed exceptions not recorded return; if (suppressedExceptions == SUPPRESSED_SENTINEL) suppressedExceptions = new ArrayList<>(1); suppressedExceptions.add(exception); }

维护了一个Throwable数组。 上面的例子,我们改一下:

@Test public void test() throws Exception { Connection conn = null; Exception e = null; try { conn = new Connection(); conn.sendData(); } catch (Exception sendDataException) { e = sendDataException; } finally { if (conn != null) { try { conn.close(); } catch (Exception closeException) { if (e != null) { e.addSuppressed(closeException); } else { e = closeException; } } } if(e!=null) { throw e; } } }

看异常信息就能同时看到两个异常了:

java.lang.Exception: send data at common.TryWithResource$Connection.sendData(TryWithResource.java:36) at common.TryWithResource.test(TryWithResource.java:13) Suppressed: java.lang.Exception: close at common.TryWithResource$Connection.close(TryWithResource.java:41) at common.TryWithResource.test(TryWithResource.java:19) ... 25 more

try-with-resources出现了

我们看到,上面的代码其实是很繁琐的,处理异常的代码比业务代码还要多。于是try-with-resources出现了,它可以在编译时将这部分处理异常代码生成,解决了异常覆盖,处理繁琐的问题。 根据 try-with-resources修改上述代码:

public void test1() throws Exception { try(Connection conn = new Connection()) { conn.sendData(); } } java.lang.Exception: send data at common.TryWithResource$Connection.sendData(TryWithResource.java:36) at common.TryWithResource.test(TryWithResource.java:13) Suppressed: java.lang.Exception: close at common.TryWithResource$Connection.close(TryWithResource.java:41) at common.TryWithResource.test(TryWithResource.java:19) ... 25 more

嗯,搞定了。

最新回复(0)