使用try-with-resources语句关闭Closeable对象

3
我有一个 Map<Key, Closeable>,如果从地图中删除键,则我想关闭 Closeable。通常,我的做法是类似于下面的代码:
Closeable c = map.remove(key);
c.close();

我的Eclipse警告我“资源'c'应该由try-with-resource管理”,所以最好只写以下内容吗?

try (Closeable c = map.remove(key)) {}

在我的特殊实现中,我有一个Closeable的子类,在这个子类中,close()方法不会抛出IOException异常,因此不需要进行异常处理。

try 块结束后,它会自动调用 c.close() - Viet
1
使用try-with-resources语句是很好的,那么你有什么问题? - Yu Jiaao
你能否提供更多关于Closeable对象的细节,为什么它们被放在一个映射中,并且当它们从该映射中移除时为什么需要关闭它们? - WilQu
1
你可以通过编写 map.remove(key).close() 来消除 c - Kevin Krumwiede
@Jerry06 我知道它的作用,我只是想知道最佳实践。 @YuJiaao 正如matoni在他的回答中所说,“空的try-with-resource看起来很奇怪”,所以我问了一下。 @KevinKrumwiede 你是对的,但这不是问题所在。 @WilQu 它用于ServerSocket进程。该映射保存活动客户端连接。在断开连接或超时时,它们将从此映射中删除,并且监听“线程”将被关闭。 - Madjosz
2个回答

5

try-with-resources 的作用是:

  • Closeable 资源的打开在 try 语句中完成
  • 资源的使用在 try 语句块内
  • close() 方法会自动调用。

因此,您建议的代码可以改为:

try(Closeable c = map.remove(key)) {}

由于您未在块内使用资源,因此不满足try-with-resource的要求。 可以推断出,在这个语句之前,您的Closeable已经打开。

我猜您有一些代码,其中打开了一堆资源,完成工作后通过遍历映射关闭它们。

这是可以接受的,有时是不可避免的。 但是,如果可能的话,最好将open()close()放在同一个方法中,将close()放在finally块中,这样您可以一眼看出每个open()都有相应的close(),并确保close()总是被调用。

MyCloseable c = MyCloseable.open(...);
try{
       // do stuff with c;
} finally {
     try {
         c.close();
     } catch (IOException e) {
         // ...
     }
}

一旦你实现了这一点,使用try-with-resources可以使代码更整洁:

try(MyCloseable c = MyCloseable.open(...)) {
    // do stuff with c;
}

如果您的需求意味着无法将打开和关闭放在同一个方法中,那么请坚持使用显式的 close() ,并忽略该警告。

理论上资源可以永远开放,因为这是客户端和服务器之间的通信,如果没有超时,客户端可以永久登录。 - Madjosz

3

如果你正在独立管理关闭操作,那么可以忽略此警告,只需调用close()即可。空的try-with-resource语句看起来很奇怪。

考虑扩展Map,这样在删除时将自动执行关闭操作:

public class CloseableMap<K,V extends Closeable> extends HashMap<K,V> {

    @Override
    public R remove(K key) {
        V resource = super.remove(key);
        if (resource != null) {
            resource.close();
        }
        return resource;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接