10.

Java 繰り返し制御文完全ガイド — for/while/拡張for

編集
この記事の要点
  • Java の繰り返しは for / while / do-while / 拡張 for-each の 4 種
  • break でループ脱出、continue で次のイテレーションへ、ラベル付きで多重ループ脱出
  • 配列・コレクション走査は 拡張 for (for-each) が簡潔で安全
  • Stream API (Java 8+)forEach / map / filter で宣言的に書く
  • 無限ループfor (;;) または while (true)。break で抜ける設計

4 種類の繰り返し構文

// 1. for ループ (回数指定)
for (int i = 0; i < 10; i++) {
    System.out.println(i);
}

// 2. while ループ (条件指定)
int n = 0;
while (n < 10) {
    System.out.println(n);
    n++;
}

// 3. do-while ループ (最低 1 回実行)
int m = 0;
do {
    System.out.println(m);
    m++;
} while (m < 10);

// 4. 拡張 for-each (コレクション走査)
int[] arr = {10, 20, 30};
for (int v : arr) {
    System.out.println(v);
}

使い分けの目安

用途推奨構文理由
0 〜 N-1 回繰り返しfor (int i = 0; i < N; i++)定型で読みやすい
配列・List 全走査拡張 for / Stream添字管理不要、ミス減
条件が満たされる間while条件が主役のとき自然
最低 1 回は実行したいdo-while入力検証ループ等
Map のキー / 値走査拡張 for + entrySet()キー値同時取得が安全
並列処理 / 集約Stream API宣言的、並列化容易

for ループの細部

// 標準
for (int i = 0; i < 10; i++) { ... }

// 逆順
for (int i = 9; i >= 0; i--) { ... }

// 2 ずつ
for (int i = 0; i < 100; i += 2) { ... }

// 複数変数
for (int i = 0, j = 100; i < j; i++, j--) { ... }

// 無限ループ
for (;;) {
    if (condition) break;
}

// インデックス + 値 (List)
List<String> list = List.of("a", "b", "c");
for (int i = 0; i < list.size(); i++) {
    System.out.println(i + ": " + list.get(i));
}

拡張 for-each (★ 推奨)

// 配列
String[] names = {"Taro", "Hanako", "Jiro"};
for (String name : names) {
    System.out.println(name);
}

// List
List<Integer> nums = List.of(1, 2, 3);
for (int n : nums) {  // ★ Integer から int への自動 unboxing
    System.out.println(n);
}

// Map (entrySet が定番)
Map<String, Integer> map = Map.of("a", 1, "b", 2);
for (Map.Entry<String, Integer> e : map.entrySet()) {
    System.out.println(e.getKey() + " = " + e.getValue());
}

// キーだけ / 値だけ
for (String k : map.keySet())   { ... }
for (Integer v : map.values())  { ... }

拡張 for の制約:

  • インデックスを取れない (必要なら for ループへ)
  • 要素の追加・削除ができない (要 Iterator または別途リスト)
  • 要素の差し替えはできない (基本型では参照のコピーになる)

break / continue

// break: ループを完全に脱出
for (int i = 0; i < 100; i++) {
    if (i == 10) break;
    System.out.println(i);
}
// → 0..9 を出力

// continue: 次のイテレーションへスキップ
for (int i = 0; i < 10; i++) {
    if (i % 2 == 0) continue;
    System.out.println(i);  // 奇数だけ
}

// ラベル付き break / continue (多重ループ脱出)
outer:
for (int i = 0; i < 5; i++) {
    for (int j = 0; j < 5; j++) {
        if (i * j > 6) {
            break outer;  // 外側のループも抜ける
        }
        System.out.println(i + "," + j);
    }
}

Iterator パターン (要素削除)

List<Integer> list = new ArrayList<>(List.of(1, 2, 3, 4, 5));

// ❌ 拡張 for 内で削除 → ConcurrentModificationException
for (Integer n : list) {
    if (n % 2 == 0) list.remove(n);   // ★ NG
}

// ✅ Iterator で削除
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
    int n = it.next();
    if (n % 2 == 0) it.remove();
}

// ✅ Java 8+ removeIf (一番簡潔)
list.removeIf(n -> n % 2 == 0);

Stream API での代替 (Java 8+)

List<Integer> nums = List.of(1, 2, 3, 4, 5);

// 各要素に処理
nums.forEach(n -> System.out.println(n));
nums.forEach(System.out::println);  // メソッド参照

// 変換 + フィルタ + 集約
int sumOfSquaresOfEven = nums.stream()
    .filter(n -> n % 2 == 0)
    .mapToInt(n -> n * n)
    .sum();   // 4 + 16 = 20

// インデックス付きで処理 (IntStream)
String[] arr = {"a", "b", "c"};
IntStream.range(0, arr.length)
    .forEach(i -> System.out.println(i + ": " + arr[i]));

// 並列処理 (要素間で副作用が無い場合のみ)
nums.parallelStream().forEach(System.out::println);

ループのパフォーマンス Tips

  • サイズ取得をループ外に: int n = list.size(); for (int i = 0; i < n; i++)
  • 配列より ArrayList は微妙に遅い。クリティカルな計算ループは配列で
  • LinkedList の get(i) は O(n)。インデックスループでは ArrayList を使う
  • 文字列連結は StringBuilderString += は毎回新規 String 生成
  • Stream の forEach は for より若干遅い。ホットループでは for を選ぶ

無限ループのパターン

// イベント駆動
while (true) {
    Event e = queue.poll();
    if (e == null) {
        Thread.sleep(100);
        continue;
    }
    if (e.isStop()) break;
    process(e);
}

// 再試行
int retry = 0;
while (true) {
    try {
        return api.call();
    } catch (IOException ex) {
        if (++retry >= 3) throw ex;
        Thread.sleep(1000 * retry);
    }
}

FAQ

Q: do-while の用途は?
A: 最低 1 回は実行したいループ。ユーザー入力検証 (「正しい入力が来るまで聞く」) や再試行ループに自然です。

Q: 拡張 for と Stream forEach どちらを使うべき?
A: 単純な走査は拡張 for で十分。filter / map / reduce 等で集約するなら Stream。並列化したいなら parallelStream

Q: ループの中で配列を変更してもよい?
A: for (int v : arr) 内で arr[i] 書き換えは可だが、List の構造変更 (add/remove) は ConcurrentModificationException。Iterator か removeIf を使う。

編集
Post Share
子ページ
  1. for文
  2. 拡張for文
  3. while文
  4. do while文
  5. continue文 (繰り返し制御文)
  6. break文
同階層のページ
  1. 基本的なルール
  2. データ型
  3. 変数
  4. 定数
  5. 配列
  6. コレクション(List,Set,Queue)
  7. Map(連想配列)
  8. 演算子
  9. 条件分岐
  10. 繰り返し制御文
  11. クラス
  12. メソッド
  13. インスタンス化
  14. コンストラクタ
  15. staticキーワード
  16. オーバーロード
  17. 継承
  18. オーバーライド
  19. this
  20. super
  21. パッケージ
  22. アクセス修飾子
  23. 抽象クラス・メソッド
  24. インターフェース
  25. カプセル化
  26. データベース接続
  27. セッション
  28. ファイル入出力
  29. ラムダ式

最近更新/作成されたページ