Наследование и Try-With-Resources - PullRequest
0 голосов
/ 29 июня 2018

Предположим, есть два класса, реализующих AutoCloseable Интерфейс, как показано ниже:

public class Closing1 implements AutoCloseable {

private boolean closed;

@Override
public void close() throws Exception {
    if (closed) {
        throw new Exception("Closed Already");
    }
    this.closed = true;
    System.out.println("Closing1 closed");
}

public boolean isClosed() {
    return closed;
}

}

и

public class Closing2 implements AutoCloseable {

private Closing1 cl1;

public Closing2(Closing1 cl1) {
    this.cl1 = cl1;
}

@Override
public void close() throws Exception {
    if(!cl1.isClosed()) {
        throw new Exception("Closing1 not closed");
    }
    System.out.println("Closing2 closed");
}

}

Я считаю, что все варианты с попытками использования ресурсов приводят к исключению! Я что-то упускаю здесь или просто разработал TWR?

        try(Closing1 c1 = new Closing1();Closing2 c2 = new Closing2(c1)){
            System.out.println("Done");
        } //Exception while auto closing C2

или

        try(Closing1 c1 = new Closing1();Closing2 c2 = new Closing2(c1)){
            System.out.println("Done");
            c1.close();
        } // exception while auto closing c1

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Сначала начните с try-with-resources, https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
Как показывает самый первый пример:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

люди не обязательно назовут все в цепочке.

Если вам явно не нужен c1 для чего-либо (кроме закрытия), в реальной жизни ваш фрагмент скорее будет выглядеть как

try(Closing2 c2 = new Closing2(new Closing1())){
    System.out.println("Done");
}

и вы бы точно не вызвали c1.close() в блоке try, поскольку с1 вообще не было бы.

Имея это в виду, выбрасывать исключение из c2, потому что содержащийся c1 не закрыт, абсолютно неверен, фактически c2 владеет объектом Closing1 и должен вызывать close() для него:

class Close1 implements AutoCloseable {
    @Override
    public void close() throws Exception {
        System.out.println("Closing c1");
    }
}

class Close2 implements AutoCloseable {
    Close1 c1;
    Close2(Close1 c1) {
        this.c1=c1;
    }

    @Override
    public void close() throws Exception {
        System.out.print("Closing c1 from c2: ");
        c1.close();
        System.out.println("Closing c2");
    }
}

void test() {
    System.out.println("Before try block");
    try(Close2 c2=new Close2(new Close1())) {
        System.out.println("In try block");
    }
    catch(Exception ex) {
        System.out.println("Exception: "+ex);
    }
    finally {
        System.out.println("In finally block");
    }
    System.out.println("After try block");
}

Однако, если кто-то дает имя c1, оно будет закрыто дважды, вот где идемпотентность входит в картину, как уже было предложено кем-то:

System.out.println("Before try block");
try(Close1 c1 = new Close1(); Close2 c2 = new Close2(c1)){
    System.out.println("In try block");
}
catch(Exception ex){
    System.out.println("Exception: "+ex);
}
finally{
    System.out.println("In finally block");
}
System.out.println("After try block");

Как уже упоминалось BufferedReader, это метод close():

public void close() throws IOException {
    synchronized (lock) {
        if (in == null)
            return;
        try {
            in.close();
        } finally {
            in = null;
            cb = null;
        }
    }
}

Если он имеет in, он закрывается и обнуляется (в блоке finally, так происходит даже в случае исключения), и все в поточно-безопасном блоке. (cb - это просто массив символов, он также обнуляется, что немного упрощает работу сборщика мусора). Из-за обнуления всего в блоке finally любые дополнительные вызовы этого же метода ничего не сделают (кроме синхронизации на мгновение с блокировкой).

0 голосов
/ 29 июня 2018

Try-with-resources закроет ресурсы в порядке, обратном их объявлению. Это означает, что c2.close() будет вызван первым, что вызовет исключение, как вы его кодировали.

...