2017-10-11 106 views
10

stream.spliterator()是否隱式關閉了stream,或者需要在之後明確關閉它?stream.spliterator()是否關閉流?

Stream<String> stream = Stream.of("a", "b", "c"); 
Spliterator<T> spliterator = stream.spliterator(); 
// Some low lever operation with the spliterator 
stream.close(); // do we need to close? 

乍一看,似乎.spliterator()方法關閉stream,但沒有叫stream.close()。至少如果我在調用.spliterator()方法後馬上關閉它,似乎不會影響分割器的操作。

Stream<String> stream = Stream.of("a", "b", "c").limit(2); 
Spliterator<T> spliterator = stream.spliterator(); 
stream.close(); 
// Some low lever operation with the spliterator 

這個問題可以被擴展到其它stream方法,例如,該.findAny()

stream.findAny() // Can I assume that I don't need to close the stream? 
stream.onClose(() -> System.out.println("hi!")).findAny()` 
// when the `onClose()` action will be called? 

原因這個問題是有深刻的清晰度當stream需要明確地關閉,在我並不需要明確地關閉它的情況下,當onClose()定義的動作將發生?

+0

Stream接口擴展了AutoCloseable接口,所以我在guest垃圾收集器處理流時會調用'onClose'動作。但最好儘快關閉它。 – Tet

+4

不,沒有垃圾收集器驅動關閉流 - 如果流有這樣一個終結器,結果將是災難性的。底層資源本身*可能*具有自動清理,但取決於資源。但這並不意味着執行任何註冊到流中的關閉處理程序。 – Holger

+2

只是爲了增加細節,這裏是一個很好的洞察流和[TWR斯圖爾特](https://stackoverflow.com/a/22929990/1746118) – nullpointer

回答

8

終端操作做從來沒有關閉流。關閉必須手動完成。唯一發生自動關閉的地方是在flatMap操作中,手動關閉通常在運行中創建的子流將介於困難和不可能之間。

這也適用於Stream.spliterator()方法。在你的例子中,它沒有區別,因爲通過Stream.of(…)創建的流不需要關閉,並且沒有onClose操作默認註冊。

您必須查閱工廠方法的文檔以確定何時需要關閉流,例如,像Files#lines(Path, Charset)一樣。

參見Does collect operation on Stream close the stream and underlying resources?Does Java 8 Stream.iterator() auto-close the stream when it's done?

+0

感謝@Holger,如果終端操作使流處於不可用狀態(例如'.findAny()'),那麼爲什麼在返回值之前終端操作沒有關閉流? – Tet

+2

@Tet:遵循關閉的責任在於資源的創建者和終端操作沒有分配資源的原則。同樣,當您讀取最後一個字節時,'InputStream'不會自動關閉。 – Holger

4

關於在Java 9中關閉Stream s,沒有什麼變化。如果底層資源應該被釋放,您仍然需要手動執行此操作。你不應該依賴垃圾收集器來做到這一點。該docs仍然說:

流有BaseStream.close()方法和實施AutoCloseable。在關閉後在流上操作將拋出IllegalStateException。大多數流實例實際上並不需要在使用後關閉,因爲它們受集合,數組或生成函數的支持,不需要特殊的資源管理。 通常,只有源數據流爲IO通道的數據流(例如Files.lines(Path)返回的數據流)需要關閉。如果流確實需要關閉,則必須在try-with-resources語句或類似的控制結構中將其作爲資源打開,以確保在其操作完成後立即關閉它。

5

spliterator()方法的調用返回一個Spliterator此流的元件和其的終端的操作。

要回答你的問題 - 不,spliterator方法或爲緣故沒有其他終端操作也不會接近流。

這代表對文件作爲terminal operations -

進行終端操作之後,流管道 視爲消耗,可以不再使用....幾乎在所有的情況下,終端操作 都是渴望,完成它們遍歷的數據源和 在返回之前處理管道。只有終端 操作iterator()spliterator(不是;這些是作爲 作爲「逃生艙口」提供的,以便在任何足以執行任務的現有操作不是 的情況下,允許任意客戶端控制的管線穿越 。

在對另一隻手關閉Stream的文檔指出: -

大部分流實例實際上並不需要使用後關閉,因爲 它們被集合爲後盾,陣列,或發生功能,其中 不需要特殊的資源管理。一般來說,只有源碼爲IO通道的數據流(例如Files.lines(Path), 返回的數據流)需要關閉。


AutoCloseable狀態以匹配IT-

這是可能的,而且實際上很常見的,一個基類來實現 AutoCloseable即使不是所有它的子類或實例將 持有可釋放資源。

這是怎麼BaseStream擴展它和close()不會影響不是通過使用資源,如Files.lines(...)的那些流遠不止這些。

然而,利用設施,如流同時支持 I/O型和非I/O類表單時,儘量與 - 資源塊是 一般不需要使用時,非I /基於O的表單。