« XPエクストリームプログラミングは偉大だ~時代がその設計思想に追いついた | トップページ | ComparableとComparatorの違いは何か »

2022/11/20

Javaのsumはreduceで置き換えられる

JavaのストリームAPIとして、sum()とreduce()をよく混同していた。
JDKのsum()の定義を読んだら、Javaのsumはreduceで置き換えられると分かった。
以下は自分用のラフなメモ書き。

IntStream (Java SE 11 & JDK 11 )

Javaのreduceの使い方は2種類ある: プログラマの思索

Java Optionalメモ(Hishidama's Java8 Optional Memo)

一般に、sumはこんな感じで使われる。
int total = items.stream().mapToInt(Item::getPrice).sum();

sumはIntStreamだけで定義されているのに、Streamでも使えると混乱していた。
だから、map()の後に使えるのか、mapToInt()の後に使えるのか混乱していた。
理由は、数値配列型のStreamでしか使えないからだろう。

もう一つは、sumの戻り値がなぜOptional型ではないのか?
averageの戻り値はOptionalDoubleだし、他の統計処理メソッドもOptionalが多いのに、なぜsumだけがint型が許されるのか?

(引用開始)
sum
int sum()
このストリーム内の要素の合計を返します。 これはリダクションの特殊な場合であり、次と同等になります。

return reduce(0, Integer::sum);

これは終端操作です。

戻り値:
このストリームの要素の合計
(引用終了)

上記の定義を読むと、sumは、 return reduce(0, Integer::sum); と同じなので、必ず初期値0が設定されているので、NULLになる可能性はなく、Optional型はなくてもいい。
sumの戻り値の型はIntegerが正しいが、オートボクシングされてint型もコンパイルOKになる。

つまり、
int total = items.stream().mapToInt(Item::getPrice).reduce(0, Integer::sum);

int total = items.stream().mapToInt(Item::getPrice).sum();
は同じ。

sumをreduceで書き換える時、こんな感じでもOK。

int total = items.stream().map(Item::getPrice).reduce((x,y) -> x+y).orElse(0);
int total = items.stream().map(Item::getPrice).reduce((x,y) -> x+y).get();
int total = items.stream().map(Item::getPrice).reduce(0, (x,y) -> x+y);

reduce(op)の戻り値はOptionalになる。
だから、Optional演算子orElse, getが必要。

一方、reduce(0, op)の戻り値はIntegerになる。
だから、戻り値はオートボクシングされてint型もOK。

IntStream.mapToInt(ToIntFunction).sum()で覚える。
Stream.map(Function,Optional>).reduce(bo)で覚える。

ちょっとややこしいのは、averageの場合、戻り値=OptionalDoubleになる。
なぜならば、DoubleStreamでaverageが定義されているから。
Optionalではない点に注意。

DoubleStream (Java SE 11 & JDK 11 )

こんな例かな。
double avg = items.stream().mapToInt(Item::getPrice).average().getAsDouble();
double avg = items.stream().mapToInt(Item::getPrice).average().orElse(0.0);

OptionalDoubleをOptionalへ変換できるか?という記事もあった。

Convert OptionalDouble to Optional - Stack Overflow

下記の記事が分かりやすい。
JavaのOptionalは、ScalaのOptionクラスに相当する。
Optional型で扱えば、空かどうかの判定を自動判定してくれるメリットがある。

Java Optionalメモ(Hishidama's Java8 Optional Memo)

「OptionalとOptionalInt等の相互変換は出来ないようだ。(継承関係も無いし、変換に使えそうなメソッドも無い)」とのことなので、OptionalとOptionalは明確に異なる。
たぶん、IntStreamの場合とStreamの場合で異なるのだろう。

|

« XPエクストリームプログラミングは偉大だ~時代がその設計思想に追いついた | トップページ | ComparableとComparatorの違いは何か »

Java」カテゴリの記事

コメント

コメントを書く



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


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



« XPエクストリームプログラミングは偉大だ~時代がその設計思想に追いついた | トップページ | ComparableとComparatorの違いは何か »