コース一覧
    Java中級:Streamと関数型
    reduce で集約する

    Java中級:Streamと関数型

    Stream APIと関数型インターフェースを学び、データ処理を宣言的で再利用しやすい形に書けるようにします。

    1
    Stream API
    01. Stream を作る5分
    02. filter で絞り込む5分
    03. map で変換する5分
    04. reduce で集約する5分
    05. collect で集める5分
    06. sorted で並び替え5分
    07. distinct で重複排除5分
    08. limit と skip5分
    09. 並列ストリーム5分
    10. Stream API まとめクイズ5分
    2
    関数型インターフェース
    01. ラムダ式の基本5分
    02. メソッド参照 ::5分
    03. Function インターフェース5分
    04. Predicate インターフェース5分
    05. Consumer と Supplier5分
    06. BiFunction と 2 引数の関数5分
    07. 関数型インターフェース まとめクイズ5分

    reduce で集約する

    合計から一歩でも外れると、手が止まる

    数値の Stream には sum() が用意されているので、合計を出すだけなら悩みません。困るのは、そこから少し外れたときです。全部の文字列を 1 本につなぎたい。いちばん大きい値だけ欲しい。そういう「まとめ方」に、専用のメソッドは用意されていません。

    かといって for に戻ると、また入れ物の変数から書き直しです。

    Java

    String all = "";
    for (String tag : tags) {
        all = all + tag;
    }

    reduce は、この「変数を 1 つ持って、要素ごとに更新していく」形をそのままメソッドにしたものです。

    Java

    String all = tags.stream().reduce("", (acc, tag) -> acc + tag);

    引数は「始まりの値」と「2 つを 1 つにする式」

    reduce に渡すものは 2 つです。1 つ目が始まりの値、2 つ目が「2 つ受け取って 1 つ返す式」です。

    上の例では、acc に「ここまでの結果」が入り、tag に「次の要素」が入ります。式が返した値が、次の呼び出しの acc になります。tags が ["a", "b", "c"] なら、"" + "a" で "a"、"a" + "b" で "ab"、"ab" + "c" で "abc" という順に育っていきます。

    同じ形で、最大値も書けます。

    Java

    int max = IntStream.of(scores)
        .reduce(Integer.MIN_VALUE, (a, b) -> Math.max(a, b));

    a が「ここまでの最大」、b が「次の点数」で、大きい方を返し続ければ、最後に残るのが全体の最大です。合計も積も連結も最大値も、変わるのは式の中身だけで、外側の形はどれも同じです。

    始まりの値は「通しても変わらない値」を選ぶ

    始まりの値は、好きな数を入れてよいわけではありません。その演算にとって「通しても結果が変わらない値」を選びます。足し算なら 0 です。0 を足しても答えは変わらないからです。文字列の連結なら空文字列です。空文字列をつないでも中身は変わりません。

    ここを外すと、結果が丸ごとずれます。連結の始まりの値に "-" を入れると、先頭に余計な - が付いた文字列が返ってきます。誰もその - を足していないのに、です。

    この選び方には、もう 1 つ得があります。要素が 1 つも無いとき、reduce は始まりの値をそのまま返します。「通しても変わらない値」を選んでおけば、空の Stream でも自然に正しい答えになるので、空かどうかを調べる if が要りません。

    解説

    どんな値を始まりに置くべきか迷ったら、要素が 1 個だけのときを考えてください。始まりの値とその 1 個を式に通して、その 1 個がそのまま返るなら正解です。

    やってみよう

    Solution.product(int[] arr) を完成させて、配列の全要素を掛け合わせた値を返してください。

    Arrays.stream(arr) または IntStream.of(arr) で IntStream を作り、reduce に始まりの値と、2 つの数を掛ける式を渡します。for や自前の累積変数は使わないでください。

    始まりの値は、掛け算にとって「通しても結果が変わらない値」を選びます。空配列を渡したときにその値がそのまま返るので、テストケースの期待値と見比べれば、選び方が合っているかどうかもすぐ分かります。

    要件

    1. Arrays.stream(arr) か IntStream.of(arr) で int[] を IntStream に変換すること
    2. reduce(1, (a, b) -> a * b) のように identity に 1 を渡して畳み込むこと (空配列でも 1 が返ることを保証する)
    3. for ループや手動の累積変数を使わず、Stream API の reduce を使って書くこと

    ヒント

    `int[]` から Stream を作るには `Arrays.stream(arr)` が一番簡単です。戻り値は `IntStream` になります

    `reduce` の第 1 引数 `identity` は「単位元」を渡します。掛け算の単位元は `1` なので、空配列のときの戻り値もそのまま `1` になります

    `(a, b) -> a * b` はラムダ式で、Stream API が「これまでの累積 `a`」と「次の要素 `b`」を渡してくれます。返した値が次の `a` になります

    生田 陸人
    監修生田 陸人
    ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
    編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

    関連レッスン

    • collect で集める

      Stream の終端操作 collect と Collectors の代表的なファクトリ (toList, toSet, toMap, joining) を学び、filter で絞り込んだ要素を joining で文字列にまとめてみよう。

    • sorted で並び替え

      Stream の sorted() で要素を昇順に並べ替え、Collectors.joining でカンマ区切り文字列に整形するテクニックを身につけよう。

    • distinct で重複排除

      Stream の `distinct()` で配列やリストから重複要素を取り除き、ユニークな要素数を集計する書き方を身につけよう。

    • limit と skip

      Stream API の中間操作 limit と skip を使い、要素を先頭から数件だけ取り出したり、先頭の数件を飛ばしたりする方法を学んで、配列のスライス処理を Stream で書いてみよう。

    このレッスンに出てくる用語

    意味があいまいなまま進んだ語は、ここから読み直せます。

    • メソッドクラスに属する関数
    • 変数データに名前をつけて参照する仕組み
    • 引数位置引数=順番で渡す。
    • 配列サイズ固定の同型データの集まり
    • テストバグを見つける工程
    • ループ繰り返し処理。矢印で戻すか専用記号で示す
    • エンドポイント「この URL を叩くとこの機能が動く」入口の住所
    • APIアプリ間でデータをやり取りする窓口
    main.java
    エディタを読み込んでいます

    メモ

    reduce で集約する

    ⌘S で保存