Как составить Closeable объекты в Java?

Я пытаюсь создать класс Java, который управляет несколькими ресурсами Closeable. Решение С++ было бы простым и легко масштабируемым с большим количеством ресурсов:

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 при сохранении безопасности исключений? Он управляется тремя ресурсами, но все больше становится громоздким. (Если это была локальная область, я мог бы просто использовать инструкцию "try-with-resources", но это не применимо здесь.)


Я думал об этом, работая с java.rmi. В конструкторе я создаю/просматриваю реестр, просматривая объекты и экспортируя объекты. Для закрытия() необходимо отменить регистрацию и исключить объекты. Я думал о создании объектов-оберток для обработки экспорта/экспорта (например, я бы сделал на С++, чтобы воспользоваться RAII), но потом я заметил, что это не поможет мне (я не настолько эксперт по Java, но я должен использовать его для университета).

В настоящий момент я использую что-то вроде ComposedResource2 выше, и он отлично работает. Но теперь мне интересно узнать, есть ли более элегантное решение.

Ответ 1

Используйте try-with-resouces, как это.

@Override
public void close() throws IOException {
    try (Closeable cc = c;
         Closeable bb = b;
         Closeable aa = a;) {
        // do nothing
    }
}

Ответ 2

Как насчет изменения close() на этом пути?

@Override
public void close() {
   close(a);
   close(b);
   close(c);
}

public void close(Closeable closeable) throws IOException{
       if (closeable != null){
            closeable.close();
       }
}

Я думаю, что его более чистый...

Также вы можете управлять тремя ресурсами как "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();

Edit:

@Mohit Kanwar предлагает выбросить исключение, таким образом:

@Override
public void close() throws IOException {
     for (Closeable r : resources){
         r.close(r);
     }
 }

И отредактировал мой код, @Lii говорит, что выполнение этого одного исключения будет препятствовать закрытию всех ресурсов, и я согласен с Lii, поэтому я отклонил Mohit edit...