拡張 for ループ
拡張 for ループ とは
配列の中身を頭から順番にぜんぶ見たいときに最適な、拡張 for (for-each) 文の書き方と使いどころを学ぼう。
拡張 for ループは「全要素を順番に見る」専用の道具
配列を扱うようになると、必ず出てくるのが「全要素を頭から順番に処理する」というパターンです。合計を求める、最大値を探す、条件に合う要素を数える、など書いていることは少しずつ違いますが、骨組みはだいたい同じです。これまで学んだ通常の for 文でも書けますが、Java には「全要素を順番に見る」専用のシンプルな構文が用意されています。それが 拡張 for ループ で、別名 for-each 文 とも呼ばれます。
拡張 for は
Java 5(2004年) で導入された構文です。それ以前はfor (int i = 0; i < arr.length; i++)と書くのが当たり前でしたが、「全要素を見るだけならインデックスは要らないのでは?」という発想から生まれました。Pythonのfor x in arr:やJavaScriptのfor...ofと同じ系統の文法です。
拡張 for の文法
拡張 for の基本形は次のとおりです。
Java
for (要素の型 変数名 : 配列やコレクション) {
// 1 要素ごとに実行したい処理
}丸カッコの中に書くのは 3 つの式ではなく、型と変数名、そしてコロン : のあとに対象の配列 だけです。たとえば int[] arr = {10, 20, 30}; を順番に表示するなら、次のように書きます。
Java
public class Solution {
public static void show() {
int[] arr = {10, 20, 30};
for (int x : arr) {
System.out.println(x);
}
}
}このコードを動かすと、10 20 30 が順番に出力されます。配列の長さや i++ などを書かなくていいので、通常の for 文に比べてだいぶスッキリします。x には arr[0] arr[1] arr[2] の値が 1 周ごとに自動で代入 されていきます。
拡張 for を読むときは「
arrの中身を順番にxに入れて回す」と頭の中で読み替えると分かりやすいです。xという名前は何でもよくて、numvalueitemのように要素の意味が伝わる名前を付けるのが好まれます。
通常の for 文と並べて比べる
同じ「合計を求める」処理を、通常の for 文と拡張 for ループの両方で書いてみましょう。違いがはっきり見えるはずです。
Java
// 通常の for 文
public class Solution {
public static int sum(int[] arr) {
int total = 0;
for (int i = 0; i < arr.length; i++) {
total += arr[i];
}
return total;
}
}Java
// 拡張 for ループ
public class Solution {
public static int sum(int[] arr) {
int total = 0;
for (int x : arr) {
total += x;
}
return total;
}
}大きな違いを並べると下のとおりです。
- インデックス変数
iが存在しない — 拡張 for ではiを書かない。arr[i]ではなく要素そのものxが直接手に入る - 長さの管理が要らない —
arr.lengthを書かなくていいので、オフバイワン (<と<=の取り違え) のミスが起きない - 初期化と更新も自動 —
int i = 0もi++も書かない。ループ条件を自分で考える必要がない
読みやすさの差は大きく、for-each で書けるところはなるべく for-each で書く、というのが Java の現代的なスタイルです。コードレビューでもインデックスを使っていないのに通常の for 文を使っていると「ここは拡張 for で書けるよ」と指摘されることがよくあります。
反復のフローを図で追ってみる
拡張 for ループの内部で何が起きているかを図にすると、次のような流れになります。
通常の for 文の「初期化 → 条件 → 本体 → 更新」のような複雑な分岐ではなく、「次の要素がある? あれば取り出して本体を実行、なければ終了」だけ、というシンプルな構造です。arr が空でも、長さが 100 でも、同じ書き方で動いてくれます。
使えないシーン — インデックスが必要 / 要素を書き換えたいとき
便利な拡張 for ですが、なんでも for-each で書けるわけではありません。使えないシーン が大きく 2 つあります。
ひとつ目は インデックス自体が欲しいとき です。たとえば「3 番目の要素だけ特別な処理をしたい」「現在の i と隣の arr[i+1] を比べたい」というようなロジックでは、i がないと書けません。このときは通常の for 文に戻ります。
Java
// インデックスが必要なケース — 通常の for を使う
for (int i = 0; i < arr.length; i++) {
if (i % 2 == 0) {
System.out.println("偶数番目: " + arr[i]);
}
}ふたつ目は 配列の要素そのものを書き換えたいとき です。これは初学者がもっとも誤解しやすい点なので、節を分けて詳しく見ていきます。
拡張 for では要素を書き換えられない
拡張 for ループの変数 x は、配列の要素の コピー であって、配列自体ではありません。だから次のようなコードを書いても、元の配列は変わりません。
Java
int[] arr = {1, 2, 3};
for (int x : arr) {
x = x * 10; // ← x は変わるが、arr は変わらない
}
System.out.println(arr[0]); // 1 のまま!x = x * 10 の行で書き換えているのは「ループ変数 x」だけで、arr[0] arr[1] arr[2] は何も変わりません。for-each で要素を更新したつもりが何も変わっていない、というのは典型的なハマりポイントです。
書き換えたい場合は、通常の for 文でインデックス越しに代入します。
Java
int[] arr = {1, 2, 3};
for (int i = 0; i < arr.length; i++) {
arr[i] = arr[i] * 10; // インデックス経由なら反映される
}
System.out.println(arr[0]); // 10
JavaScriptのArray.mapやPythonのリスト内包表記のような「ループで変換しながら新しい配列を作る」発想で来ると、拡張 for で要素を書き換えたくなりますが、Java のfor-eachはあくまで 読み取り専用 だと割り切りましょう。書き換えが必要なら通常のfor、変換した新しい配列が欲しいなら別途new int[arr.length]で受け皿を用意する、というパターンが Java らしい書き方です。
よくある間違い
拡張 for に関連して、初学者がやりがちな勘違いを 3 つ整理します。
for-eachで要素を書き換えたつもりになる —for (int x : arr) { x = ... }は元の配列に反映されない。書き換えたいときは通常のfor文を使い、arr[i]に直接代入する- コロン
:の代わりにカンマやセミコロンを使う — 通常のfor文の影響でfor (int x ; arr)やfor (int x , arr)と書いてしまう。正しいのは コロン:一文字 で、それ以外は全部コンパイルエラー - 要素の型を間違える —
int[]の配列に対してfor (String x : arr)とやるとincompatible typesのエラーになる。要素の型と一致させる必要があり、自信がなければvar(Java 10 以降) でコンパイラに推論させるのも手
おまけとして、要素を変更しないなら配列以外、たとえば List<Integer> などのコレクションでも全く同じ書き方で動きます。これは拡張 for が Iterable というインターフェースを実装したクラスすべてに対応しているからで、配列と ArrayList を行き来する Java 開発ではとても重宝します。後の章でコレクションを学ぶときも、for-each の書き方はそのまま使い回せるので、ここでしっかり身に付けておくとお得です。
ループの中身が 1 行で済むほど短いなら、Java 8 以降の
Arrays.stream(arr).sum()のような関数型 API のほうが短く書けることもあります。とはいえ拡張 for は最も基本的で、デバッガでステップ実行しやすく、エラー時の挙動も追いやすいので、まずはfor-eachを確実に書けるようになっておきましょう。
やってみよう
このレッスンの課題では、配列に含まれる 偶数の個数を数える メソッドを作ります。仕様は次のとおりです。
Solution.countEvens(int[] arr)メソッドを完成させる- 必ず拡張 for (for-each) を使う こと
- 配列の中で偶数 (
x % 2 == 0を満たす値) の個数をintで返す
例として、countEvens(new int[]{1, 2, 3, 4}) は 2 を、countEvens(new int[]{5}) は 0 を、countEvens(new int[]{2, 4, 6}) は 3 を返します。空配列なら 0 を返します。
書きながら、次の点を意識してみましょう。for (int x : arr) の x には何が入る? 偶数かどうかをどう判定する? 0 から数え始めるカウンタはどこに置く? それぞれの答えが分かれば、コードはすぐ書けます。書き上がったら、頭の中で {1, 2, 3, 4} を 1 周ずつ追って、x がどう変わって、カウンタがどう増えるかを声に出してたどってみるのがおすすめです。
もし余裕があれば、同じ処理を通常の for 文でも書いてみてください。インデックスを使う版と使わない版を見比べると、for-each のありがたみがよく分かります。次回以降のレッスンでも、「配列を順番に見るだけ」のときは for-each、「インデックスが必要」のときは通常の for、と使い分けていきましょう。
よくある質問
Q. for と while はどう使い分けますか?
A. 繰り返し回数や対象が決まっているなら for(リスト・range など)が読みやすく、終了条件が動的に決まるなら while を使います。例えば「100 回繰り返す」は for i in range(100):、「ユーザー入力が q になるまで」は while True + break が向いています。
Q. ループの途中で抜けたいときは?
A. break を使うとそのループを即座に終了します。次の周回に進みたいだけなら continue を使い、現在の処理だけスキップします。break / continue は読み手にとってジャンプ先が見えにくいため、関数化して return で抜けると意図が伝わりやすくなります。
Q. インデックスも一緒に取りたい場合は?
A. Python なら for i, v in enumerate(items):、JavaScript なら items.forEach((v, i) => ...) のようにインデックスを同時に取り出せます。手動で i = 0; i += 1 と書くと off-by-one のミスを誘発しやすいので、言語の標準機能を使うのが安全です。
次のレッスン
次は 配列クイズ で、配列の中身を頭から順番にぜんぶ見たいときに最適な、拡張 for (for-each) 文の書き方と使いどころを学ぼう を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- for-each の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. for-each とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- クラス名は
Solution、メソッド名はcountEvens、引数はint[] arr1 つ、戻り値の型はint - 繰り返しには必ず拡張 for (
for (int x : arr) { ... }の形) を使うこと - 偶数の判定は
x % 2 == 0で行うこと (負の偶数も正しくカウントされる)
入出力例
test-cases.txt
countEvens([1,2,3,4]) → 2
countEvens([5]) → 0
countEvens([2,4,6]) → 3
countEvens([]) → 0
countEvens([0,1,2,3]) → 2
countEvens([-2,-3,-4]) → 2