コース一覧
    Java中級:Streamと関数型
    filter で絞り込む

    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分

    filter で絞り込む

    数えるだけなのに、部品が 4 つ要る

    ログの行から ERROR を含む行が何本あるかを数える、というだけの処理を for で書くと次のようになります。

    Java

    int count = 0;
    for (String line : logs) {
        if (line.contains("ERROR")) {
            count++;
        }
    }

    カウンタの初期化、ループ、判定の if、そして count++。やりたいことは「ERROR の行を数える」の一言なのに、部品が 4 か所に散らばります。しかも count は途中で書き換わる変数なので、後ろに処理を足すたびに「今いくつ入っているのか」を追いかける羽目になります。

    同じ処理を Stream で書くと、こうなります。

    Java

    long count = logs.stream()
        .filter(line -> line.contains("ERROR"))
        .count();

    filter が if の役目を、count がカウンタの役目を引き受けています。書く量が減ったこと以上に、上から読むと「ログを流して、ERROR のものだけ残して、数える」とそのまま日本語になるのが利点です。

    filter は「通すか、通さないか」だけを決める

    filter に渡した line -> line.contains("ERROR") は、要素を 1 つ受け取って true か false を返す式です。Stream を流れてきた要素を 1 つずつこの式にかけて、true になったものだけを次へ通します。false になったものは、そこで捨てられます。

    大事なのは、filter が返すのもまた Stream だという点です。つまり filter を書いた時点では、まだ何も起きていません。

    Java

    logs.stream().filter(line -> line.contains("ERROR"));

    これを実行しても、1 行も判定されませんし、画面にも何も出ません。count() のように「ふつうの値」を返すメソッドを最後に呼んだ瞬間に、はじめて全体が動き出します。filter のように Stream を返すものを中間操作、count() のように値を返して打ち止めになるものを終端操作と呼びます。

    解説

    終端操作を書き忘れて「動かない」と悩むのは、Stream を覚えたての人がほぼ全員 1 度は通る道です。処理が走っていないときは、まず行末を見てください。

    元のリストは 1 件も減らない

    filter は条件に合わない要素を消しているように見えますが、logs そのものは何も変わりません。通す要素を選んで流しているだけで、元のリストは読んでいるだけです。

    Java

    List<String> logs = List.of("INFO ok", "ERROR ng", "INFO ok");
    long ng = logs.stream().filter(line -> line.contains("ERROR")).count();
    System.out.println(logs.size()); // 3 のまま

    元のリストを守ったまま別の答えを何通りも取り出せるので、同じデータに対して条件を変えながら何度でも stream() を呼べます。

    やってみよう

    Solution.evenCount(int[] arr) を完成させて、配列の中の偶数の個数を返してください。

    int[] から Stream を作るときは Arrays.stream(arr) または IntStream.of(arr) を使います。あとは通したい要素の条件を filter に渡して、最後に個数を数える終端操作を呼ぶだけです。

    型に 1 つだけ注意点があります。個数を数える count() が返すのは long で、このメソッドの戻り値は int です。そのままでは返せないので (int) でキャストしてください。

    空配列や、奇数しか入っていない配列を渡したときは 0 が返ります。if で先に長さを調べる必要はありません。要素が 1 つも通らなければ、数えた結果は自然に 0 になります。

    要件

    1. Arrays.stream(arr) または IntStream.of(arr) を使って IntStream を作ること
    2. filter にラムダ式を渡して偶数 (n % 2 == 0) だけ残すこと
    3. 終端操作 count() の戻り値 (long) を int にキャストして返すこと

    ヒント

    `Arrays.stream(arr)` は `int[]` を受け取って `IntStream` を返します。`import java.util.Arrays;` を忘れずに

    `count()` の戻り値は `long` なので、`return (int) ... .count();` のようにキャストするか `Math.toIntExact` を使います

    ラムダ式の中身は `n -> n % 2 == 0` で、偶数のときに `true` を返します。`0` や負の偶数も偶数扱いになります

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

    関連レッスン

    • map で変換する

      Stream API の map を使って要素を別の値に変換する書き方を学び、IntStream.map との違いや mapToInt の使い分けまで踏み込んで身につけよう。

    • reduce で集約する

      Stream API の `reduce` を使って配列の要素を 1 つの値に畳み込む方法を学び、整数配列の積を求めるコードを書いてみよう。

    • collect で集める

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

    • sorted で並び替え

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

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

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

    • 処理計算や代入を表す長方形
    • カウンタ数を保持して増減する典型 UI
    • ループ繰り返し処理。矢印で戻すか専用記号で示す
    • 変数データに名前をつけて参照する仕組み
    • メソッドクラスに属する関数
    • リスト順序付きで複数の値を扱うデータ構造
    • 配列サイズ固定の同型データの集まり
    • 戻り値呼び出し元への返答を表す点線矢印
    main.java
    エディタを読み込んでいます

    メモ

    filter で絞り込む

    ⌘S で保存