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;
})
しかし、明らかに、あなたは、このような保護を必要としない場合には、ラムダシンプルに保つために一般的な規則に従うべきです。