既存のStream
に新しい値を追加する良い方法はありますか?私が想像できるのは、このようなものだけです:
public <T> Stream<T> addToStream(Stream<T> stream, T elem ) {
List<T> result = stream.collect(Collectors.toList());
result.add(elem);
return result.stream();
}
しかし、私は冗長性なしにラムダ式で使用できるより簡潔なものを探しています。
[〜#〜] pecs [〜#〜]原則を実装しようとすると、別の質問が現れました。
public <T> Stream<? super T> addToStream(Stream<? super T> stream, T elem ) {
List<? super T> result = stream.collect(Collectors.toList()); //error
result.add(elem);
return result.stream();
}
ワイルドカードはStream.collect
で動作しないようで、なぜだろうと思っています。前もって感謝します。
この質問は、誤った仮定に基づいています。ストリームには実際にデータが含まれているということです。彼らはしない;ストリームはデータ構造ではなく、さまざまなデータソース全体の一括操作を指定する手段です。
Stream.concat
などの2つのストリームを1つに結合するためのコンビネーターと、既知の要素のセット(Stream.of
)またはコレクション(Collection.stream
)からストリームを作成するためのファクトリーがあります。したがって、新しい要素を記述する新しいストリームとともに、手元にあるストリームを連結した新しいストリームを作成する場合は、これらを組み合わせることができます。
PECSの例の問題は、? super T
が3回出現し、同じタイプを記述していると仮定しているが、そうではないことです。ワイルドカードが出現するたびに一意のキャプチャに対応しますが、これは望みではありません。その型変数に名前を付けて、リストの型と入力ストリームの型が同じであることをコンパイラーが認識するようにする必要があります。 (また、コレクションを具体化しないでください。これは高価で、ストリームが有限でない場合は終了しない可能性があります。concatを使用してください。)答えは次のとおりです。これを行う1つの方法を次に示します。
public<T> Stream<T> appendToStream(Stream<? extends T> stream, T element) {
return Stream.concat(stream, Stream.of(element));
}
ストリームに「挿入」することを考えていたため、実際にはストリームから消費しているため、PECSと混同しました。
どう?
return Stream.concat(stream, Stream.of(elem));
これは、元のストリームが有限であると仮定しています。そうでない場合は、逆の順序で連結できます。
StreamEx ライブラリには、適切な#prepend()
および#append()
メソッドがあります。以下に、それらの使用方法の例を示します。
StreamEx.of("second").prepend("first").append("third").forEach(System.out::println);
出力は次のとおりです。
first
second
third
最良の方法は、flatMapを次のように使用することです。
public <T> Stream<T> appendToStream(Stream<T> stream, T element) {
return stream.flatMap(e -> Stream.of(e, element));
}
これは元のストリームで動作するため、ストリームに対する単なる別の中間操作になります。例:
stream.flatMap(e -> Stream.of(e, element))
.map(...)
.filter(...)
.collect(Collectors.toList());