如何用Java编写可关联对象?

时间:2015-12-15 07:52:27

标签: java

我正在尝试创建一个管理多个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之类的内容,而且效果很好。但现在我有兴趣知道是否有更优雅的解决方案。

2 个答案:

答案 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的编辑...