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
Stream.map(Function
ちょっとややこしいのは、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
下記の記事が分かりやすい。
JavaのOptionalは、ScalaのOptionクラスに相当する。
Optional型で扱えば、空かどうかの判定を自動判定してくれるメリットがある。
Java Optionalメモ(Hishidama's Java8 Optional Memo)
「OptionalとOptionalInt等の相互変換は出来ないようだ。(継承関係も無いし、変換に使えそうなメソッドも無い)」とのことなので、OptionalとOptional
たぶん、IntStreamの場合とStreamの場合で異なるのだろう。
| 固定リンク
「Java」カテゴリの記事
- パッケージ原則とクラス原則の違いは何なのか(2023.10.14)
- パッケージ設計の原則の意義は変化しているのか(2023.09.30)
- ChatGPTにEclipseでEclEmmaとJaCoCoからカバレッジを出力する方法を聞いた(2023.02.01)
- JavaGold SE11の感想(2022.12.25)
- ComparableとComparatorの違いは何か(2022.11.20)
コメント