在没有新对象实例的情况下使用 try-with-resources 是错误的形式吗?

Is using try-with-resources without a new object instance bad form?

一般来说,我总是看到 try-with-resources 用于分配 new object instance which close() method在超出范围时被调用。

据我所知,创建新对象不是必需的,try-with-resources 语法只需要一个局部变量来在超出范围时调用 close()。因此,您可以使用它来控制 "paired operations",例如从池中分配一些东西并确保它被返回。

例如,下面的 MyHandle 显示了如何在不再需要时释放池化实例:

// init
class MyHandle implements AutoCloseable {
    boolean inUse = false; 
    public MyHandle allocate() {
        inUse = true;
        return this;
    }

    public void close() {
       inUse = false;
    }
}

MyHandle[] pool = new MyHandle[POOL_SIZE];
for (int i = 0; i < pool.length; i++) {
    pool[i] = new MyHandle(i);
}

// allocate
MyHandle allocateFromPool() {
    for (int i = 0; i < pool.length; i++) {
        if (!pool[i].inUse)
            return pool[i].allocate();
    }
    throw new Exception("pool depleted");
}

// using resources from the pool

try (MyHandle handle = allocateFromPool()) {
   // do something
}
// at this point, inUse==false for that handle...

这被认为是错误的形式吗?

编辑:我想我是在问是否有更好的替代方法来构建这种逻辑,或者在使用上述方法时是否存在一些主要缺点。我发现在库中使用它可以得到一个干净的 API.

编辑 2:请忽略代码示例中的问题,我将其内联写入 SO 文本框中,以通过某种示例阐明我的问题。显然这不是真正的代码! :)

try-with-resource 语法旨在作为一种语法糖,让您确保处置对象,无论处置逻辑是什么。在您的情况下,它将对象返回到池中。像这样使用 try-with-resource 绝对没有错。它可能不是最常见的用例,但绝对是一个有效的用例。

在幕后,大多数资源(例如文件描述符)实际上是由操作系统从池中分配的,然后在关闭时返回到池中。

以这种方式使用 try-with-resources 是完全有效的。

N.B。尽管您的代码示例存在严重的线程问题,但我认为为了清楚起见,已经删除了必要的线程安全性问题。我提到它只是因为人们不应该复制你的代码并在实现中使用它。

这样的 try-with-resources 没有错。但在你的情况下,我会担心意外重用已从另一个线程重新打开的关闭句柄。

一点间接就可以解决这个问题,return MyHandleWrapper 而不是直接访问 MyHandle (allocateFromPool 将 return MyHandleWrapper 的新实例)。它 不会! 解决所有其他线程问题。

public class MyHandleWrapper extends MyHandle {
    private MyHandle handle;
    private boolean closed;

    public void close() {
        if(!closed){
            handle.inUse = false;
        }
        closed = true;
    }

    public void read() {
        if (closed) {
            throw new IllegalStateException("Already closed");
        }
        handle.read();
    }
}

基本上,如果句柄在 MyHandleWrapper 中关闭,您会保留信息。您使用该标志保护对 handle 的任何状态更改访问,如有必要,抛出适当的异常。