Streams combiner
メソッドでreduce
が果たす役割を完全に理解できない。
たとえば、次のコードはコンパイルされません。
int length = asList("str1", "str2").stream()
.reduce(0, (accumulatedInt, str) -> accumulatedInt + str.length());
コンパイルエラー:(引数の不一致; intはJava.lang.Stringに変換できません)
しかし、このコードはコンパイルします:
int length = asList("str1", "str2").stream()
.reduce(0, (accumulatedInt, str ) -> accumulatedInt + str.length(),
(accumulatedInt, accumulatedInt2) -> accumulatedInt + accumulatedInt2);
コンバイナメソッドは並列ストリームで使用されることを理解しています。したがって、この例では、2つの中間累積整数を加算しています。
しかし、最初の例がコンバイナなしではコンパイルできない理由、またはコンバイナが2つのintを加算するだけなので、文字列からintへの変換をどのように解決するのかを理解できません。
誰もこれに光を当てることができますか?
使用しようとしたreduce
の2つと3つの引数バージョンは、accumulator
に同じ型を受け入れません。
2つの引数reduce
は、 定義 です。
T reduce(T identity,
BinaryOperator<T> accumulator)
あなたの場合、Tは文字列なので、BinaryOperator<T>
は2つの文字列引数を受け入れ、文字列を返す必要があります。しかし、intとStringを渡すと、コンパイルエラーargument mismatch; int cannot be converted to Java.lang.String
が発生します。実際、文字列が期待されている(T)ため、ID値として0を渡すことも間違っていると思います。
また、このバージョンのreduceはTのストリームを処理し、Tを返すため、これを使用してStringのストリームをintに減らすことはできません。
3つの引数reduce
は 定義 です。
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
あなたの場合、Uは整数で、Tは文字列です。したがって、このメソッドは文字列のストリームを整数に減らします。
BiFunction<U,? super T,U>
アキュムレーターには、2つの異なるタイプ(Uおよび?スーパーT)のパラメーターを渡すことができます。これらのパラメーターは、整数とストリングです。さらに、ID値Uは整数を受け入れますので、0を渡しても問題ありません。
あなたが望むものを達成する別の方法:
int length = asList("str1", "str2").stream().mapToInt (s -> s.length())
.reduce(0, (accumulatedInt, len) -> accumulatedInt + len);
ここで、ストリームのタイプはreduce
の戻り値のタイプと一致するため、reduce
の2つのパラメーターバージョンを使用できます。
もちろん、reduce
を使用する必要はまったくありません。
int length = asList("str1", "str2").stream().mapToInt (s -> s.length())
.sum();
概念を明確にするために落書きと矢印が好きなので...始めましょう!
4つの文字列があるとします。目標は、そのような文字列を1つに連結することです。基本的にはタイプで開始し、同じタイプで終了します。
あなたはこれを達成することができます
String res = Arrays.asList("one", "two","three","four")
.stream()
.reduce("",
(accumulatedStr, str) -> accumulatedStr + str); //accumulator
これにより、何が起こっているかを視覚化できます。
アキュムレータ関数は、(赤)ストリーム内の要素を段階的に変換して、最終的に削減された(緑)値に変換します。アキュムレータ関数は、単にString
オブジェクトを別のString
に変換します。
同じ4つの文字列があるとします。新しい目標はそれらの長さを合計することであり、ストリームを並列化することです。
必要なのは次のようなものです:
int length = Arrays.asList("one", "two","three","four")
.parallelStream()
.reduce(0,
(accumulatedInt, str) -> accumulatedInt + str.length(), //accumulator
(accumulatedInt, accumulatedInt2) -> accumulatedInt + accumulatedInt2); //combiner
これは何が起こっているかのスキームです
ここで、アキュムレータ関数(BiFunction
)を使用すると、String
データをint
データに変換できます。ストリームは並列であるため、2つの部分(赤)に分割されます。各部分は互いに独立して作成され、同様に多くの部分的な(オレンジ)結果が生成されます。部分的なint
の結果を最終(緑色)int
の1つにマージするためのルールを提供するには、コンバイナを定義する必要があります。
ストリームを並列化したくない場合はどうしますか?とにかく、コンバイナを提供する必要がありますが、部分的な結果が生成されないため、コンバイナは呼び出されません。
combinerなしで2つの異なるタイプを取るreduceバージョンはありません(なぜこれが要件であるかはわかりません)。 accumulatorが連想的でなければならないという事実により、このインターフェースはほとんど役に立たなくなります。
list.stream().reduce(identity,
accumulator,
combiner);
次と同じ結果を生成します。
list.stream().map(i -> accumulator(identity, i))
.reduce(identity,
combiner);