如何确保资源被释放,具有嵌套的对象层次结构?
How to make sure resource is released, with nested object hierarchy?
我有这样的代码(简化版):
class A {
B b = new B();
void close() {
b.close();
}
}
class B {
Closeable mustBeClosed = new Closeable() {
{
System.out.println("create");
}
@Override
public void close() {
System.out.println("close");
}
};
int n = 0 / 0;
void close() {
mustBeClosed.close();
}
}
//code
try (A a = new A()) {
//do something
}
如何保证mustBeClosed被释放?
当对象层次结构复杂时,可能会发生这种情况。 Override finalize for B 可能不是一个完美的解决方案。
针对这个问题有什么最佳实践或原则吗?
修改后的版本如下:
class B {
Closeable mustBeClosed;
B() {
try {
mustBeClosed = ...
//other initialization which might raise exceptions
} catch (throwable t) {
close();
throw t;
}
}
void close() {
if (mustBeClosed != null) {
try {
mustBeClosed.close();
} catch (Throwable t) {
}
}
//all other resources that should be closed
}
}
然而,这需要太多的代码并且远非优雅。更重要的是,所有权层次结构中的所有 类 似乎都应遵循相同的样式,这会产生大量代码。
有什么建议吗?
使用包装器方法关闭所有 Closeable
个实例正常。
closeGraceFully(Closeable c) { // call this guy for all instances of closeable
try{
c.close();
} catch(IOException ex) {
// nothing can be done here, frankly.
}
}
然后调用这个包装器方法。不要直接调用 close()
。不要使用 finalizers
它们是邪恶的,会减慢您的应用程序。
你的问题是如果构造函数抛出异常,try-with-resources 不会(实际上不能)调用close()
。
任何分配资源的对象构造,并有可能在构造过程中失败在分配资源之后,必须释放那个异常之前的资源级联调用堆栈。
两种解决方法:
1) 确保资源分配是最后执行的操作。在您的情况下,这意味着将字段 n
向上移动到字段 mustBeClosed
.
之前
2) 在构造函数中处理资源构造,而不是在字段初始值设定项中,因此您可以捕获任何后续异常并在重新抛出异常之前再次释放资源,如您的替代解决方案所示。
但是,您不必在 close()
方法中进行空检查,因为如果对象构造成功,mustBeClosed
将始终为非空,如果对象构造成功,则无法调用 close()
施工失败。
我有这样的代码(简化版):
class A {
B b = new B();
void close() {
b.close();
}
}
class B {
Closeable mustBeClosed = new Closeable() {
{
System.out.println("create");
}
@Override
public void close() {
System.out.println("close");
}
};
int n = 0 / 0;
void close() {
mustBeClosed.close();
}
}
//code
try (A a = new A()) {
//do something
}
如何保证mustBeClosed被释放?
当对象层次结构复杂时,可能会发生这种情况。 Override finalize for B 可能不是一个完美的解决方案。
针对这个问题有什么最佳实践或原则吗?
修改后的版本如下:
class B {
Closeable mustBeClosed;
B() {
try {
mustBeClosed = ...
//other initialization which might raise exceptions
} catch (throwable t) {
close();
throw t;
}
}
void close() {
if (mustBeClosed != null) {
try {
mustBeClosed.close();
} catch (Throwable t) {
}
}
//all other resources that should be closed
}
}
然而,这需要太多的代码并且远非优雅。更重要的是,所有权层次结构中的所有 类 似乎都应遵循相同的样式,这会产生大量代码。
有什么建议吗?
使用包装器方法关闭所有 Closeable
个实例正常。
closeGraceFully(Closeable c) { // call this guy for all instances of closeable
try{
c.close();
} catch(IOException ex) {
// nothing can be done here, frankly.
}
}
然后调用这个包装器方法。不要直接调用 close()
。不要使用 finalizers
它们是邪恶的,会减慢您的应用程序。
你的问题是如果构造函数抛出异常,try-with-resources 不会(实际上不能)调用close()
。
任何分配资源的对象构造,并有可能在构造过程中失败在分配资源之后,必须释放那个异常之前的资源级联调用堆栈。
两种解决方法:
1) 确保资源分配是最后执行的操作。在您的情况下,这意味着将字段 n
向上移动到字段 mustBeClosed
.
2) 在构造函数中处理资源构造,而不是在字段初始值设定项中,因此您可以捕获任何后续异常并在重新抛出异常之前再次释放资源,如您的替代解决方案所示。
但是,您不必在 close()
方法中进行空检查,因为如果对象构造成功,mustBeClosed
将始终为非空,如果对象构造成功,则无法调用 close()
施工失败。