2016-01-16 8 views
7

これはよく知られていJavadocが言うことについてStreamインタフェース:マップされたストリームを閉じる - そのアイデアは何ですか?

は、StreamsはBaseStream.close()メソッドを持っているとAutoCloseableを実装し、 が、ほぼすべてのストリーム・インスタンスは、実際に使用した後 を閉じてする必要はありません。 一般に、ソースがIOチャネルであるストリームのみ(Files.lines(Path、Charset)によって返されるような など)は、閉じるを必要とします。 ほとんどのストリームは、特別なリソース管理を必要としない、コレクション、配列、または 関数の生成をサポートしています。

がOK(。ストリーム は閉鎖を要求する場合、それは のtry-と資源文のリソースとして宣言することができる)が、同時に、このインタフェースでflatMapToIntのような方法があります。

IntStream flatMapToInt(Function<? super T, ? extends IntStream> mapper); 

はのJavadoc仕様は言う:その内容は このストリームに置かれた後

各マッピングされたストリームが閉じられています。

だから、IntStreamがソースでIOチャネルを持つように設計されていない場合、なぜこの方法で閉じられますか?例えば

ReferencePipeline実装がこのようにそれをしない、:

try (IntStream result = mapper.apply(u)) {  
    if (result != null) 
     result.sequential().forEach(downstreamAsInt); 
} 

もっと一般的な質問は次のようになります。私たちはIntStream(またはその子孫)か否かなどのクロージング・ストリームを気にする必要がありますか?そうでなければ、なぜflatMapTo*が気になるのですか?

EDIT @Tunakiは非常に興味深いemail linkを提供しています。しかし、これはすべて約flatMapです。ここで私は一般的な場合にストリームを終了する必要があります。しかし、私の質問は特別なケースについてです:flatMapToIntflatMapToLongなど、ストリームを閉じる必要はありません。

EDIT-2 @BrianGoetzは、ここに訴え、それは彼の引用電子メールであるので、そのため彼は対象になっている:)

+6

'flatMapToInt'を' flatMap'とは違って扱うことは意味がありません。 'IntStream'はリソースも保持できます。末尾から出てくるものが 'int'であるからといって、ソースが非メモリリソースで始まらなかったというわけではありません。たとえば、各要素が 'Files.lines()。mapToInt(String :: length)'にフラットマップされる 'flatMapToInt'を実行するとします。 –

答えて

14

リソース取り扱いに関する一般的なルールは、そのwhoever is responsible for closing a resource is the one that opened itです。 flatMap操作はストリームAPIでStreamを開く唯一の操作であるため、これを閉じる操作は唯一の操作です。 this mailから引用

、ブライアン・ゲッツは言った:

を要約すると、flatMap()は内部的に完了した後 ストリームを閉じ操作のみで、正当な理由のために - それは 唯一のケースでありますストリームは操作自体によって効果的に開かれるため、操作によっても を閉じる必要があります。その他のストリームは、発信者によって開かれた と仮定されているため、発信者によって閉じられる必要があります。

この例は次のとおりです。検討

try (Stream<Path> paths = Files.walk(dir)) { 
    Stream<String> stream = paths.flatMap(p -> { 
     try { 
      return Files.lines(p); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    }); 
} 

ファイルの行のStream<String>を返すFiles::lines方法参照。フラット・マッピング操作が終了すると、ファイルを読み取るために使用されたオープンされたリソースがクローズされることが予想される。問題は、何によって閉じられたのか?最初にストリームを開いた操作なので、flatMap自体によって閉じられました。

Files.linesは、基底のBufferedReaderを閉じる事前登録されたクローズハンドラを持つStreamを返します。 flatMap操作が完了すると、このクローズハンドラが呼び出され、リソースが正しく解放されます。


このアイデアはflatMapTo*操作にバックポートされている理由は、同じである:プロセスによって割り当てられたすべてのリソースは、そのプロセスによって閉じなければならない上記の規則に付着します。

閉じるリソースを持つIntStreamを構築することができることを示すには、次のストリームパイプラインを考慮してください。各パスはその行にフラットマッピングされず、各行の文字数になります。

try (Stream<Path> paths = Files.walk(dir)) { 
    IntStream stream = paths.flatMapToInt(p -> { 
     try { 
      return Files.lines(p).mapToInt(String::length); 
     } catch (IOException e) { 
      throw new UncheckedIOException(e); 
     } 
    }); 
} 
+0

*他のストリームは呼び出し元によって開かれたものとみなされるので、呼び出し元によって閉じられるべきである* - これは、 'try-with-resourse 'ですべてのストリーム(' list.stream() ') '建設?? – Andremoniy

+1

@Andremoniyストリームの大半はノーオペレーションになります。関係する唯一のものは、閉鎖すべき基礎となる資源を扱うものである。 – Tunaki

+0

「フラットマップ」の場合は同意しますが、「Int/LongStream」のアイデアが残っています – Andremoniy

関連する問題