我正在尝试创建一个管理多个Closeable
资源的Java类。 C ++解决方案非常简单,可以通过大量资源轻松扩展:
class composed_resource
{
resource_a a;
resource_b b;
resource_c c;
composed_resource(int x)
: a(x), b(x), c(x)
{ }
~composed_resource()
{ }
};
我天真的Java解决方案:
public class ComposedResource implements Closeable
{
private final ResourceA a;
private final ResourceB b;
private final ResourceC c;
public ComposedResource(int x) /* throws ... */ {
a = new ResourceA(x);
try {
b = new ResourceB(x);
try {
c = new ResourceC(x);
} catch (Throwable t) {
b.close();
throw t;
}
} catch (Throwable t) {
a.close();
throw t;
}
}
@Override
public void close() throws IOException {
try {
a.close();
} finally {
try {
b.close();
} finally {
c.close();
}
}
}
}
略有改进的版本:
public class ComposedResource2 implements Closeable
{
private final ResourceA a;
private final ResourceB b;
private final ResourceC c;
public ComposedResource2(int x) /* throws ... */ {
try {
a = new ResourceA(x);
b = new ResourceB(x);
c = new ResourceC(x);
} catch (Throwable t) {
close();
throw t;
}
}
@Override
public void close() throws IOException {
try {
if (a != null) a.close();
} finally {
try {
if (b != null) b.close();
} finally {
if (c != null) c.close();
}
}
}
}
是否有一个更优雅的解决方案,避免嵌套的try-catch-blocks,同时仍然保持异常安全?它可以通过三种资源进行管理,但更多的是变得笨拙。 (如果是本地范围,我可以使用"尝试使用资源"声明,但这不适用于此。)
我在使用java.rmi
时想到了这一点。在构造函数中,我创建/查找注册表,查找对象和导出对象。 close()需要取消注册和取消导出对象。我想创建包装器对象来处理导出/取消导出(就像我在C ++中做的那样利用RAII),但后来我发现这对我没什么帮助(我不是那样的)很多Java专家,但我必须将它用于大学)。
目前我正在使用上面ComposedResource2
之类的内容,而且效果很好。但现在我有兴趣知道是否有更优雅的解决方案。
答案 0 :(得分:11)
使用像这样的try-with-resouces。
@Override
public void close() throws IOException {
try (Closeable cc = c;
Closeable bb = b;
Closeable aa = a;) {
// do nothing
}
}
答案 1 :(得分:1)
如何以这种方式更改close()?
@Override
public void close() {
close(a);
close(b);
close(c);
}
public void close(Closeable closeable) throws IOException{
if (closeable != null){
closeable.close();
}
}
我认为它更干净......
此外,您可以将3个资源作为“Closeables”进行管理,并将它们放在一个数组中,以便ComposedResource拥有您想要的尽可能多的资源。做这样的事情:
public class ComposedResource{
List<Closeable> resources = new ArrayList<Closeable>();
public void add(Closeable c){
resources.add(c);
}
@Override
public void close(){
for (Closeable r : resources){
close(r);
}
}
public void close(Closeable c){
try{
c.close();
catch (IOException e){
log(e);
}
}
}
所以你将添加资源:
ComposedResource c = new ComposedResource();
c.add(new Resource1());
c.add(new Resource2());
c.add(new Resource3());
...
// do nice thinks
// and, to close;
c.close();
编辑:
@Mohit Kanwar建议以这种方式抛出异常:@Override
public void close() throws IOException {
for (Closeable r : resources){
r.close(r);
}
}
编辑了我的代码,@ Lii说,做这个例外将阻止关闭所有资源,我同意Lii所以我拒绝了Mohit的编辑...