私はI / Oベースのストリームのためにしてみてください-とリソースflatMap中を使用する必要がありますか?

マルクスMalkusch:

AはStreamれるAutoCloseableと、I / O系の場合に使用されるべきであるtry-with-resourceブロック。何介して挿入されている中間のI / OベースのストリームについてflatMap()例:

try (var foos = foos()) {
   return foos.flatMap(Foo::bars).toArray(Bar[]::new);
}

try (var foos = foos()) {
  return foos.flatMap(foo -> {
    try (var bars = foo.bars()) {
      return bars;
    }
  }).toArray(Bar[]::new);
}

flatMap()ドキュメントは言います:

その内容は、この流れの中に置かれた後、各マッピングされたストリームが閉じられています。

まあ、それは幸せな道です。何の間で例外が起こった場合は?そのストリームは、その後、閉じられていない、潜在的に漏出するリソースをご利用いただけますか?私は、常に使用するべきtry-with-resource中間ストリームにも?

ホルガー:

以下のような構造では意味がありません

return foos.flatMap(foo -> {
    try (var bars = foo.bars()) {
        return bars;
    }
}).toArray(Bar[]::new);

そのようストリームを閉じてしまう前に、それはサブストリームが完全に使用できなくなり、呼び出し元に返されます。

関数のコードは、終値が関数の外にある適切な場所、でどうなることを保証するために実際には、それは不可能です。それは確かにAPIの設計者は、あなたがする必要はありませんし、ストリームの実装が世話をすることを決めた理由です。

また、これは例外的な場合に適用されます。関数は、ストリームに戻った後のストリームは、まだ、ストリームが閉じされることを保証します:

try {
    IntStream.range(1, 3)
        .flatMap(i -> {
            System.out.println("creating "+i);
            return IntStream.range('a', 'a'+i)
                    .peek(j -> {
                        System.out.println("processing sub "+i+" - "+(char)j);
                        if(j=='b') throw new IllegalStateException();
                    })
                    .onClose(() -> System.out.println("closing "+i));
        })
        .forEach(i -> System.out.println("consuming "+(char)i));
} catch(IllegalStateException ex) {
    System.out.println("caught "+ex);
}
creating 1
processing sub 1 - a
consuming a
closing 1
creating 2
processing sub 2 - a
consuming a
processing sub 2 - b
closing 2
caught java.lang.IllegalStateException

あなたは構築ストリームが常に閉じていることを確認するために、条件にプレイしてもよいです。処理されません外ストリームの要素については、まったくのストリームは存在しません。

以下のようなストリーム動作のため.flatMap(Foo::bars).flatMap(foo -> foo.bars())、あなたは一度と仮定することができますbars()正常に作成され、ストリームを返し、それは必ず、適切に閉じられたために、呼び出し側に渡されます。

異なるシナリオが失敗する可能性があり、ストリームの作成後に操作を実行する機能をマッピングすることになる、例えば

.flatMap(foo -> {
    Stream<Type> s = foo.bar();
    anotherOperation(); // Stream is not closed if this throws
    return s;
})

この場合、例外的なケースでは、唯一の例外的なケースで閉鎖を確保するために必要な次のようになります。

.flatMap(foo -> {
    Stream<Type> s = foo.bar();
    try {
        anotherOperation();
    } catch(Throwable t) {
        try(s) { throw t; } // close and do addSuppressed if follow-up error
    }
    return s;
})

しかし、明らかに、あなたは、このような保護を必要としない場合には、ラムダシンプルに保つために一般的な規則に従うべきです。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=173713&siteId=1