MEDIA

メディア

  1. TOP
  2. メディア
  3. プログラミング
  4. Java拡張for文を完全解説|基本構文・配列/コレクション処理・例外回避まで総まとめ

Java拡張for文を完全解説|基本構文・配列/コレクション処理・例外回避まで総まとめ

Javaで配列やコレクションを扱うとき、拡張for文(Enhanced for loop)はもっとも使用頻度の高い構文のひとつです。しかし、拡張for文は簡潔で便利な一方で、内部仕様や制限を正しく理解しないまま使われるケースも多く、開発現場では思わぬ不具合を生むことがあります。

そのため、本記事では拡張for文の仕組み・具体的な書き方・通常for文との明確な使い分け・注意点を体系的に解説します。


拡張for文とは何か|Java 5で導入された背景と目的

まず、拡張for文は、配列やコレクションの反復処理をよりシンプルに、安全に書くために設計された構文です。従来のfor文では「初期化・条件式・カウンタ更新」という3つのステップが必要でしたが、拡張for文では要素を直接受け取るだけで反復処理が完了します。

さらに、この構文はJava 5(2004年)でGenerics(総称型)やAutoBoxingと共に導入され、Javaの型安全性と可読性を大きく向上させる役割を担ってきました。

なぜ通常のforでは不十分だったのか

一方で、通常のfor文は「柔軟性が高い」反面、単純なループ処理においては次のような課題がありました。

  • インデックス(i)の管理が煩雑で、範囲外アクセスなどのバグが生まれやすい。
  • Iterator を手動で扱うコードは記述が長く、読み手にとってノイズになる。
  • リストから要素を取り出す list.get(i) のような定型コードが繰り返し発生する。

こうした背景から、要素を「先頭から順番に取り出すだけ」の処理を簡潔に書くための専用構文として、拡張for文が定着しました。


拡張for文の基本構文と使い方|配列・List・Set・Mapの実例

拡張for文の基本構文は非常にシンプルで、直感的に記述できます。

for (要素の型 変数名 : 配列またはコレクション) {
    // 要素を使った処理
}

このように、インデックスやイテレータを意識することなく、変数に要素が順番に代入されていきます。

配列の基本パターン

配列を処理する場合、もっとも短い記述で全要素にアクセスできます。

String[] names = {"田中", "鈴木", "佐藤"};

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

しかし、配列の「一部だけ(例:先頭から3つ)」を扱いたい場合や、「現在の要素が何番目か」を知る必要がある場合は、通常のfor文の方が適しています。

配列に対する拡張for文は、コンパイル時に内部的にインデックスベースのループへ変換され、効率的に動作します。詳細な仕様はJava言語仕様 JLS 14.14.2で確認できます。

List・Setの処理

コレクションフレームワーク(List, Setなど)も同様に処理できます。

List<Integer> nums = List.of(10, 20, 30);

for (int n : nums) { // AutoUnboxingによりInteger→intへ自動変換
    System.out.println(n);
}

Listは格納された順番通りに、Setは実装クラス(HashSetなど)の仕様に応じた順序で要素が取り出されます。

Mapの例(entrySetを活用する)

Mapは直接ループさせることができません。そのため、キーと値を同時に扱いたい場合は、entrySet() を使うのがベストプラクティスです。

Map<String, Integer> scores = Map.of("A", 90, "B", 80);

for (Map.Entry<String, Integer> e : scores.entrySet()) {
    System.out.println(e.getKey() + ":" + e.getValue());
}

keySet()values() で回すことも可能ですが、キーと値の両方が必要な場面では entrySet() の方が効率的です。詳しい仕様は Oracle公式Javaドキュメント(Map解説) も参照してください。


通常for文との違いと「使い分け」戦略

拡張for文は非常に便利ですが、万能ではありません。したがって、実務では明確な使い分けが必要です。

indexを扱いたい場合は通常のfor文

拡張for文には「現在のインデックス」を取得する機能がありません。そのため、次のようなケースでは通常のfor文が推奨されます。

  • インデックスを使いたい場合: 「◯番目のデータ」というログを出力したいときなど。
  • 特定の要素だけ処理したい場合: 「偶数番目のみ」「後ろから逆順に」といった処理。
  • ループを細かく制御したい場合: 途中でカウンタを飛ばしたり、戻したりする特殊なロジック。
  • 要素の入れ替えが必要な場合: ソートロジックの実装など。

コレクション変更が必要な場合の判断基準

さらに、ループしながらコレクションの要素を「削除・追加」したい場合、拡張for文は不向きです。

  • 拡張for文: ループ中の構造変更(add/remove)は原則禁止(例外が発生する)。
  • Iterator: remove() メソッドを使えば安全に削除可能。
  • 通常for文: インデックスを操作しながら削除できるが、バグを生みやすいため注意が必要。

このように、単純な読み取り以外では、拡張for文以外の選択肢を検討する必要があります。


拡張for文の注意点と安全な書き方

拡張for文を使用する際、もっとも注意すべきなのが ConcurrentModificationException(並行変更例外) です。コレクションに対する拡張for文は、内部的に Iterator を使用して動作します。

そのため、Iteratorを経由せずにリストの要素を直接削除(list.remove())すると、整合性が取れなくなり例外がスローされます。

ConcurrentModificationExceptionを防ぐための対策

ループ処理中に要素を削除したい場合、以下のいずれかの方法を採用します。

1. Java 8以降なら removeIf を使う(推奨)

もっとも安全でモダンな方法は、Collection#removeIf メソッドを使うことです。

List<String> list = new ArrayList<>(List.of("A", "B", "C"));

// ループを使わず、条件に一致する要素を一括削除
list.removeIf(s -> s.equals("B"));

2. Iterator を明示的に使う

細かい制御が必要な場合は、Iteratorを手動で取得して回します。

Iterator<String> it = list.iterator();
while(it.hasNext()) {
    String s = it.next();
    if (s.equals("B")) {
        it.remove(); // 安全に削除可能
    }
}

これらの対策を押さえるだけで、反復処理の安全性が大きく向上します。詳細は APIドキュメント(removeIf) などで確認できます。


まとめ|拡張for文を使いこなすための要点整理

最後に、Javaの拡張for文を使いこなすためのポイントを整理します。

  • 拡張for文は、配列やコレクションを簡潔に記述するための強力な構文です。
  • インデックス操作が不要で、先頭から順番に処理するだけなら拡張for文が第一選択です。
  • Mapを処理する場合は、entrySet() を使うのが定石です。
  • ループ中に要素を削除したい場合は、拡張for文ではなく removeIfIterator を使用して例外を防ぎましょう。

実務では「読み取るだけなら拡張for」「細かい制御や変更が必要なら通常forまたはIterator」という判断基準を持つことで、バグの少ない保守性の高いコードを書くことができます。

つまずいたら、現役エンジニアと一緒に解決しよう

この記事で扱った【Java】は、独学だと細部で詰まりやすい分野です。さらに理解を深めたい方は、Zerocode Onlineで実務直結の学習を進めてみませんか。

現役エンジニア1on1

コード添削・詰まり解消を丁寧にサポート。

実務設計まで網羅

Java/SQL/Spring Bootを体系的に習得。

ポートフォリオ支援

現場で刺さる成果物づくりを伴走。

完全オンライン

時間と場所を選ばず学べます。

Join us! 未経験からエンジニアに挑戦できる環境で自分の可能性を信じてみよう 採用ページを見る→

記事監修

ドライブライン編集部

[ この記事をシェアする ]

記事一覧へ戻る