在没有新对象实例的情况下使用 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
的任何状态更改访问,如有必要,抛出适当的异常。
一般来说,我总是看到 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
的任何状态更改访问,如有必要,抛出适当的异常。