コレクションを通常返す場所にストリームを返すのは正気ですか?


19

レガシーコードに関連付けられていないAPIを開発しているとき、結果を収集することで純粋にStreamsパイプラインで終了するメソッドを作成していることがよくあります。このように:

ImmutableSet<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfThing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey)
        .collect(MyCustomCollectors.toImmutableSet());
}

さて、このクラスのほとんどのクライアントは通常、要素を検索してそれを反復処理するためにコレクション(この場合はImmutableSet)を必要としますが、一部のクライアントはその上にいくつかの操作をパイプできるようにストリームを持つことで利益を得ることができますコレクションから新しいストリームを取得する必要のないストリーム。したがって、ストリームを返すと、コレクションを持っている場合のオプションのスーパーセットがクライアントに提供されます(結局、常にcollect()ストリーム自体を使用できます:

Stream<T> deriveSomethingMeaningfulFromPrivateState() {
    return myPrivateThingies.stream()
        .map(this::ownerOfthing)
        .map(Owner::socialStatus)
        .filter(SocialStatus::isHeAFineMatey);
        // No collect
}

このアプローチは、潜在的な欠陥が見当たらないため、試してみたいと思います。しかし、どのライブラリでもこのアプローチを見たことはありません(おそらく、Java 8の登場後にリリースされたライブラリが多くなかったためです)。既存のライブラリクラスは、通常、プライベート状態から何かを派生するときにコレクションを返します。

Java 8より前の自分がコレクションを返す場所にストリームを返すことにした場合に発生する可能性のある悪いことがありますか?または、私はここで私的状態から派生したすべてのものでアンチパターンの何かをしていますか?

回答:


14

myPrivateThingiesが可変の場合、プライベート状態とストリーム結果の間に隠された依存関係が作成されています。クライアントが間接的にmyPrivateThingies状態を変更する可能性がある場合、クライアントcollectは最初に配布することを意図したものとは異なる結果を呼び出します。

myPrivateThingiesが不変の場合、結果は参照的に透過的になりますが、注意する必要があるもう1つの問題があります。セマンティックガベージ、つまり、不要になった大量のメモリを保持することです。仮定myPrivateThingies非常に大きく、ストリームを収集した結果が小さいです。クライアントは、ストリームを生成したオブジェクトへのすべての参照を破棄した後も、ストリームを保持しstream続けることがありますが、それでもmyPrivateThingiesガベージコレクションにならないようにします。結果を熱心に収集myPrivateThingiesすることで、解放されます。

これは、Java 7を呼び出すときに実際に発生しましたsubstring。オラクルは、サブストリングを毎回コピーしないことによる潜在的な効率の節約は、過度のメモリ消費を持つ平均的なユーザーを驚かせる価値がない場合があると判断しました。それは古い振る舞い(パーサーなど)の実際のユースケースがなかったということではありませんが、結果を熱心に収集することはしばしば十分に速く、それが起こったときあなたは長所も潜在的な詐欺もありません。

一方、ストリームを返すことにより、クライアントが結果を保持するために使用するデータ構造を選択できるようになります。両方のオプションを提供する価値があるかもしれません。


4

考慮すべき最も重要なこと:Streamsは1回しか反復できませんが、aよりも柔軟性がありCollectionます:結果に対して追加の反復処理を行うために、さらにStreamsまたはs を作成し続けることができIteratorます。

そのため、メソッドの呼び出し元が結果を1回だけ使用するかどうかわからない場合は、を返すことをお勧めしますCollection


サンプルコードには明らかなエラーが1つあります。なぜSocialStatusaに人という概念があるのheでしょうか?


3

私の見解では、いいえ。ストリームでできることは、コレクションでできることの厳密なスーパーセットであり、多くの場合、より効率的にすることができます。そのため、不慣れなこと以外は使用しない理由はありません。「ラムダ式はJava 8へのゲートウェイ薬ですが、ストリームは真の依存症です。」(Venkat Subramaniam、Javaでの関数型プログラミング

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.