« Go言語でできることは何なのか | トップページ | astahとExcelの間でマインドマップをやり取りする方法はコピペだけ »

2022/11/13

Javaのreduceの使い方は2種類ある

Javaのreduceの戻り値が異なるのに戸惑っていた。
Javaのreduceの使い方は2種類ある。
ラフなメモ。

【参考】
Java:Streamのreduceの使用方法 | GWT Center

Stream BinaryOperator(Java Platform SE 8 )


Javaのreduceは、Rubyのreduceみたいに、累積する処理みたいなもの。
MapRedcueの間柄のように、map関数とreduce関数はペアで考える。

reduceの引数はBinaryOperator型になるのは分かる。
合計値のように、2つの引数を累積させる処理を行って、1つの戻り値を返すだけ。

しかし、reduce(BinaryOperator)とreduce(初期値, BinaryOperator)は戻り値の型が異なるのに混同していた。
結論は、初期値を設定していなければ、戻り値が空の場合があるのでOptionalでラッピングして返す。
Optionalであれば、NullPointerExceptionのリスクを無くせるメリットがある。

reduceの引数に初期値を設定していれば、戻り値がなくても初期値をそのまま返せばいい。
つまり、戻り値はプリミティブ型でも問題ない。

Java:Streamのreduceの使用方法 | GWT Centerの説明がわかりやすかった。
以下引用している。

【パターン1】Optional reduce(BinaryOperator accumulator)
戻り値がない場合があるので、Optionalで返す。

// 何らかの要素があったか
boolean foundAny = false;
// 最終結果
T result = null;
for (T element : このストリームの要素を列挙する) {
if (!foundAny) {
// 最初の要素の場合
foundAny = true;
result = element;
} else {
// 二番目以降の要素の場合
result = accumulator.apply(result, element);
}
}
// 結果があればそれを返す。なければ空を返す
return foundAny ? Optional.of(result) : Optional.empty();

【パターン2】T reduce(T identity, BinaryOperator accumulator)

初期値が与えられているので「値が存在しない」ということは無く、戻り値はOptionalではない。

// 初期値
T result = identity;
for (T element : このストリームの要素を列挙する) {
// 初期値に加算していく
result = accumulator.apply(result, element);
}
return result;

IntStream (Java SE 11 & JDK 11 )には、reduceの考え方が書かれている。
これは参考になる。

int reduce​(int identity, IntBinaryOperator op)
指定された単位元の値と結合的な累積関数を使ってこのストリームの要素に対してリダクションを実行し、リデュースされた値を返します。 これは、次の操作に相当します。

int result = identity;
for (int element : this stream)
result = accumulator.applyAsInt(result, element)
return result;

つまり、reduceは何らかのアルゴリズムに添って累積させる処理を行っている。
その累積処理は抽象化されているので、アルゴリズムにラムダ式を当てはめれば汎用的に使えるわけだ。

|

« Go言語でできることは何なのか | トップページ | astahとExcelの間でマインドマップをやり取りする方法はコピペだけ »

Java」カテゴリの記事

コメント

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



« Go言語でできることは何なのか | トップページ | astahとExcelの間でマインドマップをやり取りする方法はコピペだけ »