【问题标题】:Correctly closing resources in constructor and close method in case of error在错误的情况下正确关闭构造函数和关闭方法中的资源
【发布时间】:2021-03-20 16:37:52
【问题描述】:
给定一个AutoCloseable 类MyClass,它在其构造函数中创建多个SomeResource 类型的资源。 SomeResource 也实现了AutoCloseable 并且它的构造函数和它的close 方法都可能抛出一个IOException。我如何最好地确保:
- a) 构造过程中发生故障时,构造函数会正确关闭所有打开的资源
- b)
close 方法在关闭其中一个资源时正确关闭所有资源以防万一。
这是示例类:
public class MyClass implements AutoCloseable {
private final SomeResource resource1;
private final SomeResource resource2;
private final SomeResource resource3;
MyClass() throws IOException {
resource1 = new SomeResource();
resource2 = new SomeResource();
resource3 = new SomeResource();
}
@Override public void close() throws IOException {
resource1.close();
resource2.close();
resource3.close();
}
}
【问题讨论】:
标签:
java
try-with-resources
【解决方案1】:
a) 构造函数不能使用 try-with-resources 或 try-finally,因为资源不会被关闭,以防资源创建成功。取而代之的是,在创建资源之后应该有一个 try-catch 块,以确保在创建资源后出现任何错误时关闭资源。在 catch 块内,必须重新抛出异常,以免丢失。
b) close 方法可以使用 try-with-resource 块来确保所有资源都已关闭
public class MyClass implements AutoCloseable {
private final SomeResource resource1;
private final SomeResource resource2;
private final SomeResource resource3;
MyClass() throws IOException {
resource1 = new SomeResource();
try {
resource2 = new SomeResource();
try {
resource3 = new SomeResource();
} catch (IOException | RuntimeException e) {
closeIgnoreException(resource2);
throw e;
}
} catch (IOException | RuntimeException e) {
closeIgnoreException(resource1);
throw e;
}
}
private static void closeIgnoreException(AutoCloseable autoCloseable) {
try { autoCloseable.close(); } catch (Exception ignore) {}
}
@Override
public void close() throws IOException {
try (resource1;
resource2;
resource3) {}
}
}
在 Java 9 之前,try-with-resources 语句不接受任何引用。因此close方法必须通过以下方式实现:
public void close() throws IOException {
try (SomeResource r1 = resource1;
SomeResource r2 = resource2;
SomeResource r3 = resource3) {}
}