Ответ 1
Используйте try-with-resouces, как это.
@Override
public void close() throws IOException {
try (Closeable cc = c;
Closeable bb = b;
Closeable aa = a;) {
// do nothing
}
}
Я пытаюсь создать класс 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
выше, и он отлично работает. Но теперь мне интересно узнать, есть ли более элегантное решение.
Используйте try-with-resouces, как это.
@Override
public void close() throws IOException {
try (Closeable cc = c;
Closeable bb = b;
Closeable aa = a;) {
// do nothing
}
}
Как насчет изменения 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...