簡體   English   中英

繼承和嘗試資源

[英]Inheritance and Try-With-Resources

假設有兩個類實現了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

Try-with-resources將按照聲明的相反順序關閉資源。 這意味着將首先調用c2.close() ,這將在編碼后引發異常。

首先從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");
}

並且您肯定不會在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塊中的所有內容都設為空,因此對該同一個方法的任何額外調用都不會做任何事情(除了暫時同步鎖之外)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM