2009-10-05 25 views
10

Java中的InputStreams和OutputStreams close()銷燬了嗎?我完全理解這可能是不好的形式(尤其是C和C++世界),但我很好奇。Input/OutputStreams是否關閉銷燬?

此外,假設我有以下代碼:

private void foo() 
{ 
    final string file = "bar.txt"; 
    Properties p = new Properties(); 
    p.load(new FileInputStream(file)); 
    //... 
} 

是否無名的FileInputStream超出範圍p.load()之後,因此被摧毀,有點像C++作用域規則?我試圖在Google上搜索Java的匿名變量作用域,但那並沒有達到我想的效果。

謝謝。

+0

謝謝大家的幫助! – Calyth

+0

請注意,在Java 7或更高版本中嘗試使用資源可以解決此問題相對簡單的操作(只需要一個額外的變量賦值,當然還有'try'本身)。另外請注意,上面的代碼會在我的Eclipse環境中生成警告(關於缺少的關閉)。 –

回答

16

第一個答案:在Java中沒有「破壞」(在C++意義上)。只有垃圾收集器,當它看到一個已經準備好收集的對象時,它可能醒來或者不能完成它的工作。 Java中的GC通常是不可信的。

第二個答案:有時是的,有時沒有,但不值得冒險過去。從Elliote Rusty Harold's Java IO

並非所有的流需要關閉—字節數組輸出流不 需要關閉,例如。但是,與文件 和網絡連接關聯的流應始終在您完成後關閉。 例如,如果您打開一個文件進行寫入,並忽略關閉它,當您通過 時,則其他進程可能被阻止讀取,或者 寫入該文件。

根據Harold的說法,輸入或輸出流也是如此。有一些例外(他注意到了System.in),但總的來說,如果在完成時沒有關閉文件流,則會帶來風險。並且在finally塊中關閉它們,以確保即使拋出異常也會關閉它們。

5

不,Java中沒有析構函數。對該對象可能還有其他引用,即使在對該對象的特定引用超出了範圍(或被修改)之後。如果對象不再可達,那麼流可能會在稍後調用它的終結器,這將關閉流。

Properties.load是特殊的,它關閉傳遞給它的流。 編輯:Properties.loadFromXML是我似乎一直在思考五年左右的特殊方法。 (API文檔應該在之前而不是之後說。)謝謝@tzimnoch。

+0

沒有析構函數,但有終結器。而來自java.io DO的大部分InputStream/OuputStream類的終結器會關閉該流。 – ChssPly76

+5

@ ChssPly76:沒錯,但是不管什麼時候,甚至是否終結者都會被調用。沒有。 –

+1

https://docs.oracle.com/javase/7/docs/api/java/util/Properties.html#load(java.io.InputStream)「指定的流在此方法返回後保持打開狀態。」 – tzimnoch

3

變量超出範圍,因此被銷燬。但是在Java中,變量對象之間存在非常大的區別,變量指向

指向的對象僅在變量超出範圍時才被銷燬。該對象只有在Java運行時引擎決定感覺像是要銷燬未被任何範圍內變量指向的對象時纔會被銷燬。

6

我曾經假設流最終會通過垃圾回收自動關閉,但是有趣的證據表明,未能手動關閉它們會導致資源泄漏。你會希望做這樣的事情,而不是:

InputStream stream = null; 

try { 
    stream = new FileInputStream("bar.txt"); 
    Properties p = new Properties(); 
    p.load(stream); 
} 
catch(Exception e) { 
    // error handling 
} 
finally { 
    closeQuietly(stream); 
} 

closeQuietly()是Apache的公地IO庫上IOUtils的方法。

3

簡短的回答是「也許,但不要打賭!」。

實現FileInputStream的類堆棧中的某個地方有一個finalizer類,它將在運行時有效關閉流(並釋放資源)。

問題是,並不能保證終結器將永遠運行。從JLS(12.6節)報價:

Java編程語言不 指定終結將如何很快 調用,只是說,對於 目標被重新將 存儲之前發生。

這使得流定稿問題:

  1. 如果你的Stream對象永遠不會成爲垃圾,它永遠不會被敲定。
  2. 如果您的Stream對象被終結,它可能需要很長時間才能被垃圾收集和最終確定。
  3. 在執行終結器之前,JVM可能需要執行額外的GC週期,此對象被標識爲不可訪問。這是JLS肯定允許的!
  4. 從技術上講,JVM永遠不會執行終結器,前提是它永遠不會重複使用終結器對象存儲。 (我不知道有任何生產質量的JVM採用這條線,但你永遠不知道......)
+0

我會認爲如果JVM資源不足,它會確定關閉的文件對象。 (不要寬恕不能自行清理。) –

+0

您可能會認爲...但AFAIK,用完文件描述符不會觸發GC運行,它會檢測到其他流對象現在可以(假設)可以終止。 –

+0

@mike瓊斯:不,事實並非如此。這可以被實踐證明。減少內存可能會觸發垃圾收集(它甚至要求在拋出'OutOfMemoryError'之前盡力而爲),但gc與finalization不同*。垃圾收集會導致帶終結器的對象被排入隊列以等待以後完成,但是在完成時將完全未定義。因此,儘管文件描述符(或任何其他非內存資源)耗盡不會觸發gc(正如Stephen已經指出的那樣),即使gc被觸發,也不會強制結束。 – Holger