Java | 拡張for と Stream API の書き換え比較(for→stream)

Java Java
スポンサーリンク

拡張 for 文(for-each)と Stream API(ラムダ式) の違い・使い分けは、実務で必ず押さえておくべきポイントです。
ここでは以下の流れで分かりやすく整理します。


全体構成

  1. 【基礎】for-each と Stream の思想の違い
  2. 【書き換え例①】出力処理
  3. 【書き換え例②】フィルタ処理(条件で抽出)
  4. 【書き換え例③】集計処理(合計・平均)
  5. 【書き換え例④】オブジェクト加工(DTO変換)
  6. 【まとめ】どっちを使う?実務判断チャート

1. 基礎:for-each と Stream の思想の違い

観点拡張 for 文Stream API
書き方命令的(どう処理するかを書く)宣言的(何をしたいかを書く)
特徴わかりやすく、直感的簡潔で強力、関数型スタイル
処理手続き的に順に実行メソッドチェーンで処理を流す
並列化自前でスレッド制御が必要parallelStream() で簡単並列化
主な用途簡単な走査・入門・小規模処理フィルタ・集計・変換・大量データ

2. 書き換え例①:出力処理(for → Stream)

拡張 for 文版

List<String> names = List.of("Suzuki", "Tanaka", "Sato");

for (String name : names) {
    System.out.println(name);
}
Java

Stream API 版

names.forEach(System.out::println);
Java

🗝️ ポイント:

  • forEach は Stream の中でも使えるが、List 自体にも forEach がある。
  • 処理が1行で完結。副作用(printlnなど)を行う場合にシンプル。

3. 書き換え例②:フィルタ処理(条件で抽出)

拡張 for 文版

List<String> list = List.of("apple", "banana", "avocado");
List<String> result = new ArrayList<>();

for (String s : list) {
    if (s.startsWith("a")) {
        result.add(s);
    }
}

System.out.println(result); // [apple, avocado]
Java

Stream API 版

List<String> result = list.stream()
    .filter(s -> s.startsWith("a"))
    .toList();

System.out.println(result);
Java

🗝️ ポイント:

  • filter() が「条件で選ぶ」操作。
  • toList() で結果をリスト化(Java 16+)。
  • for に比べて 「何をしたいか」 が明確。

4. 書き換え例③:集計処理(合計・平均)

拡張 for 文版

int[] scores = {80, 90, 75, 100};
int sum = 0;
for (int s : scores) {
    sum += s;
}
System.out.println("合計: " + sum);
Java

Stream API 版

int sum = Arrays.stream(scores)
    .sum();

System.out.println("合計: " + sum);
Java

🗝️ ポイント:

  • Arrays.stream() で配列を Stream 化。
  • 合計・平均・最大最小はすでにメソッドが用意されている:
    • .sum(), .average(), .max(), .min()

5. 書き換え例④:オブジェクト変換(DTO → ViewModel)

拡張 for 文版

class User {
    String name;
    int age;
    User(String n, int a) { name = n; age = a; }
}

List<User> users = List.of(
    new User("Suzuki", 30),
    new User("Tanaka", 20),
    new User("Sato", 25)
);

List<String> names = new ArrayList<>();
for (User u : users) {
    names.add(u.name.toUpperCase());
}

System.out.println(names); // [SUZUKI, TANAKA, SATO]
Java

Stream API 版

List<String> names = users.stream()
    .map(u -> u.name.toUpperCase())
    .toList();

System.out.println(names);
Java

🗝️ ポイント:

  • map() は要素を「別の形に変換」する処理。
  • DTOの変換、JSON整形、画面表示用データの生成などに最適。

6. 書き換え例⑤:条件抽出+集計(複合処理)

拡張 for 文版

List<Integer> nums = List.of(3, 10, 7, 2, 12);
int sum = 0;
for (int n : nums) {
    if (n >= 5) {
        sum += n;
    }
}
System.out.println(sum); // 29
Java

Stream API 版

int sum = nums.stream()
    .filter(n -> n >= 5)
    .mapToInt(Integer::intValue)
    .sum();

System.out.println(sum);
Java

🗝️ ポイント:

  • filtermapToIntsum のように、パイプラインで流れを表現できる。
  • for よりも「意図(5以上を合計)」が明確。

7. 並列処理(拡張forでは困難なこと)

Stream API の強み

大量データを扱うとき、拡張 for では逐次処理だが、Stream なら簡単に並列化できます:

list.parallelStream()
    .filter(x -> x.length() > 3)
    .forEach(System.out::println);
Java

🗝️ 注意点:

  • 並列処理(parallelStream())は順序保証がなくなる。
  • IO処理や状態を持つ操作(書き込みなど)には不向き。

8. 実務での使い分け(まとめ表)

処理のタイプ拡張 for 文Stream API
単純な出力・ログ◎(可読性が高い)
条件でフィルタ◎(filterが明確)
集計(合計・平均など)
オブジェクト変換◎(mapが便利)
ネストループ△(読みにくくなる)
並列処理◎(parallelStream)
小規模処理
大規模データ処理

実務判断チャート

▼ 配列やリストを順に処理したい
 └→ インデックスが必要? → はい → 通常の for
              ↓いいえ
  └→ シンプルな処理? → はい → 拡張 for
              ↓いいえ(加工・集計・条件分岐が多い)
    └→ Stream API

まとめ(実務ベストプラクティス)

  • 単純な繰り返し → 拡張 for 文でOK(読みやすくて安全)
  • 集計・変換・条件抽出などの“処理の流れ” → Stream API が強い
  • チーム開発では:
    • 小規模・明快なループ → 拡張 for
    • 中~大規模・変換+集計 → Stream
  • どちらも混在OK。
    ⇒ 「ループの目的を最も明確に書ける方法」を選ぶのが正解。

Java
スポンサーリンク
シェアする
@lifehackerをフォローする
スポンサーリンク
タイトルとURLをコピーしました