使用try-with-resources而没有新的对象实例坏表单?

时间:2016-07-29 10:36:41

标签: java try-with-resources

通常情况下,我总是看到用于分配新对象实例 的try-with-resources,其close()方法在调出时被调用-of-范围。

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

例如,下面的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文本框中内联编写,以某种方式使我的问题清楚。显然它不是真正的代码! :)

3 个答案:

答案 0 :(得分:10)

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

答案 1 :(得分:4)

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

以这种方式使用try-with-resources非常有效。

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

答案 2 :(得分:2)

尝试使用这样的资源没有错。但在你的情况下,我会担心重新使用已经从另一个线程重新开放的已关闭句柄。

一个小的间接会解决这个问题,返回MyHandleWrapper而不是直接访问MyHandle(allocateFromPool将返回MyHandleWrapper的新实例)。它将 not!解决所有其他线程问题。

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的访问权限,必要时会抛出相应的例外。