继承和尝试资源

时间:2018-06-29 18:53:36

标签: java try-with-resources try-with

假设有两个实现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 :(得分:4)

Try-with-resources将按照声明的相反顺序关闭资源。这意味着c2.close()将首先被调用,这将按照您的编码方式引发异常。

答案 1 :(得分:1)

首先尝试资源,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");
}

并且您肯定不会在try块中调用c1.close(),因为根本没有c1。

请牢记这一点,因为所包含的c1尚未关闭,因此从c2引发异常是完全错误的,实际上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块中的所有内容都设为空,因此对该同一个方法的任何额外调用都不会做任何事情(除了暂时同步锁之外)。