try-with-resources 调用 close() 失败

Posted

技术标签:

【中文标题】try-with-resources 调用 close() 失败【英文标题】:try-with-resources fails to call close() 【发布时间】:2015-03-26 10:12:30 【问题描述】:

我正在使用方便的 try-with-resources 语句来关闭连接。这在大多数情况下效果很好,但只有在一种非常简单的方法中它不能正常工作。即,这里:

public boolean testConnection(SapConnection connection) 
  SapConnect connect = createConnection(connection);
  try ( SapApi sapApi = connect.connect() ) 
    return ( sapApi != null );
   catch (JCoException e) 
    throw new UncheckedConnectionException("...", e);
  

sapApi 对象非空,该方法返回 true,但从不调用 sapApi 的 close() 方法。我现在求助于使用 finally 块,它工作正常。但这很令人费解。 Java 字节码还包含对关闭的调用。有没有人见过这种行为?

编辑澄清情况:

这是 SapApi,它当然实现了 AutoCloseable。

class SapApi implements AutoCloseable 

  @Override
  public void close() throws JCoException 
    connection.close(); // this line is not hit when leaving testConnection(..)
  
..

以下是与 testConnection(..) 在同一类中的另一个方法。这里 SapApi.close() 在返回之前被调用。

@Override
public List<Characteristic> selectCharacteristics(SapConnect aConnection,   InfoProvider aInfoProvider) 
  try (SapApi sapi = aConnection.connect()) 
    return sapi.getCharacteristics(aInfoProvider);
   catch ( Exception e ) 
    throw new UncheckedConnectionException(e.getMessage(), e);
  

编辑 2: 这是 SapConnect.connect():

SapApi connect() 
  try 
    ... // some setup of the connection
    return new SapApi(this); // single return statement
   catch (Exception e) 
    throw new RuntimeException(e);
  

SapApi 没有子类。上面的 close 方法只有一种实现。特别是没有空的close()。

【问题讨论】:

为了调用 close(),SapApi 必须实现 Closeable 接口,或者至少实现 java.lang.AutoCloseable。是这样的吗? 不只有 AutoCloseable 是必需的吗? Closeable 扩展了 AutoCloseable。 对,但 AutoClosable 更通用(抛出 java.lang.Exception),在谈论连接时,Closable 更合适,因为它会抛出 IOException。 您的代码无法编译,可能性 #1:如果 SapApi 实现了 AutoCloseable,您将需要捕获 IOException(或者您的方法将使用 throws IOException 声明)。可能性 #2:如果 SapApi 没有实现 AutoCloseable,那么编译器无论如何都会抱怨,因为资源的 try-catch 中只允许自动关闭 AutoClosable 抛出异常而不是 IOException,但你是对的...... 【参考方案1】:

为了调用 close(),SapApi 必须实现 AutoCloseable 接口,但是既然我们在谈论连接,那么 SapApi 最好实现抛出 IOException 的 Closable 接口。

阅读: http://tutorials.jenkov.com/java-exception-handling/try-with-resources.html

【讨论】:

SapApi 实现了 AutoCloseable 并且它的 close 方法在同一个类的其他上下文中被调用。【参考方案2】:

我不知道你说的是什么

这在大多数情况下都很好用

1 通常SapApi 在 try-with-resources 中使用时会关闭

2 它通常适用于SapApi以外的资源

我是根据数字 2 的假设来回答的。

Try-with-resources 仅适用于 Java 7 中实现 AutoCloseable 接口的资源。所以我的第一个建议是让您检查SapConnectSapApi(无论它们是什么)的API,以确定是否是这种情况。

【讨论】:

在同一个类中有相当多的方法在正确调用 close() 的完全相同的表达式(try-with-resources)中使用 SapApi 类。只有这一种方法不起作用。【参考方案3】:

一个猜测:可能connect 返回 SapApi 的子类或代理类。如果没有进行任何更改,close 将被覆盖以不执行任何操作,否则仅调用 super.close()

我会给出答案,因为即使没有调用任何方法,AutoCloseable 也可以工作。

【讨论】:

以上是关于try-with-resources 调用 close() 失败的主要内容,如果未能解决你的问题,请参考以下文章

try-with-resources 调用 close() 失败

try-with-resource vs java.lang.IllegalStateException:提交响应后无法调用 sendError()

try-with-resources

在 try-with-resource 中手动关闭

Java7里try-with-resources分析

我应该在 try-with-resources 语句中声明每个资源吗?