2016-12-18 40 views
2

之前創建由於Java 7中,我們可以使用try與資源:使用的資源,爲

try (One one = new One(); Two two = new Two()) { 
    System.out.println("try"); 
} catch (Exception ex) { ... } 

現在的問題是,爲什麼我必須建立在try語句來的對象?爲什麼不允許我這樣的語句之前創建的對象:

One one = new One(); 
try (one; Two two = new Two()) { 
    System.out.println("try"); 
} catch (Exception ex) { ... } 

我看不出有任何理由,爲什麼這應該是一個問題。雖然我收到錯誤消息「在此語言級別不支持資源引用」。我將我的IDE(IntelliJ IDEA)設置爲Java 8,因此應該可以工作。有沒有很好的理由,不允許?

+0

因爲如果在構造函數中拋出異常,您將無法捕獲異常。 – Maroun

+0

是的,這可能是我的原因,我同意。我是否正確,這只是他們做出的選擇 - 可以允許外部創建對象 - 我們只是不會捕獲那裏創建的異常 - 對嗎? –

+0

對實例的'try'沒有意義,在已經創建的實例中沒有邏輯。但是,在建設過程中,您可能會遇到例外情況。 – Maroun

回答

4

您不必在try-with-resources語句中創建對象,只需聲明一些實現AutoCloseable的類型的局部變量即可。這些變量實際上是最終的,並且作用域爲try塊,它允許編譯器使用它們來生成清理所需的樣板文件。

FileInputStream f1 = new FileInputStream("test1.xml"); 
FileInputStream f2 = new FileInputStream("test2.xml"); 
// Don't need to create the resources here, just need to declare some vars 
try (InputStream in1 = f1; InputStream in2 = f2) { 
    // error; in1 is final 
    in1 = new FileInputStream("t"); 
} 

Better Resource Management with Java SE 7: Beyond Syntactic Sugar

+0

你有一個想法,爲什麼我們必須聲明一個新的變量,它的範圍是'try'語句?這對我來說似乎沒有必要 - 是否有一個很好的理由呢? –

+0

當然,編譯器需要一個最終的本地引用來執行清理,但我想不出爲什麼如果我們被允許傳入一個資源引用就不能創建一個。 – teppic

+0

我想這裏的想法是,資源引用可能不是最終的,因此更好地創建一個新的最終本地引用。自動創建一個可能是可能的,但可能會導致混淆。我很驚訝,在'try'模塊之外創建一個最終引用並傳遞它也是不允許的,因爲我認爲這應該是有效的代碼。可能不允許再次避免混淆。 –

2

它實際上是可能的:

One one = new One(); 
try (One temp = one; ....;) { 

} 

然而,幾乎從來沒有一個很好的理由來創建嘗試與 - 資源之前的資源。因此try-with-resources塊要求你在資源列表中聲明一個新的變量(這也很容易強制該變量是最終的)。你可以做上面的事實更可能不想過於嚴格(例如,如何從One temp = someMethod(),其中someMethod既可以創建一個新的或返回一個現有實例One temp = one不同的副作用。

創建資源嘗試與資源塊之前的資源可能會導致微妙的錯誤,因爲如果在輸入塊之前發生異常,則資源未正確關閉(例如,如果您在創建One和輸入try-with-resources塊之間做其他事情)

一般而言,在關閉資源之後,您應該沒有理由訪問資源,因此您應該將範圍限制爲資源打開的時間(即嘗試使用資源urces塊)。如果在關閉資源後確實需要訪問某個資源,則可能需要考慮另一種設計,其中(可關閉)資源與關閉資源後所需的對象/數據分開,或者需要使用嵌套嘗試與資源塊。

例外情況是,如果傳入一個AutoCloseable,並且您的方法必須保證它在退出時被關閉,但這通常是一種設計異味:打開資源的方法也應負責關閉它。