読み込み中...

【Java】10ステップで完全理解!拡張for文の活用法

Java拡張for文の使い方とサンプルコードを詳細に説明した画像 Java
この記事は約24分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaの拡張for文は、配列やListなどの要素を先頭から順に取り出す構文です。インデックスを直接扱わないため、プログラミング入門でも読みやすい反復処理を書けます。

ただし、要素の削除、添字が必要な処理、例外、forEachやラムダ式との使い分けには注意が必要です。Java基本文法として形だけでなく、通常のfor文へ切り替える場面まで整理すると、プログラミング学習の理解が安定します。

動作確認環境
  • Java 21
  • OpenJDK 21 / javac 21
📖 この記事で学べること
  • 拡張for文の構文と通常のfor文との違い
  • 配列、List、二次元配列での実用的な書き方
  • 条件分岐、メソッド、独自クラスとの組み合わせ
  • 削除処理や添字が必要な場面での判断基準
  • ラムダ式やforEachとの使い分け

拡張for文の基本

拡張for文は「全要素を順番に読む」処理に向いたJava基本文法です。最小形はfor (型 変数 : 配列またはIterable)で、右側のデータから要素を取り出し、左側の変数へ順に代入します。

int[] numbers = {1, 2, 3};

for (int number : numbers) {
    System.out.println(number);
}

結果: 期待される出力は、123が行ごとに表示される形です。

numberはループごとに現在の要素を受け取ります。iの初期化、i < numbers.lengthの条件、i++の更新式は不要です。

公式ドキュメントによれば、拡張for文は配列とIterableを実装したオブジェクトに使えるのが基本です。構文の根拠はJava Language Specification 14.14.2で確認できるのが基本です。

ただし、拡張for文は現在の添字を直接持ちません。添字を使う処理は通常のfor文、要素だけで完結する処理は拡張for文と分けると、コーディングテクニックとして判断しやすくなります。

定義と特徴

拡張for文は、enhanced for statementやfor-each loopとも呼ばれますし、ここがポイントです。Javaではforキーワードを使いますが、通常のfor (初期化; 条件; 更新)とは構造が異なります。

配列の全件表示、リスト内の集計、文字列リストのチェックでは、添字より要素そのものに関心があるのが目安です。String item : itemsなら「itemsの各要素をitemとして扱う」と読み取れますが、これは押さえたい点です。

breakcontinueは通常のループと同じように使えます。条件に合う要素で止める、特定の値だけ飛ばす処理も書けます。

💡 Tips: プログラミング入門では、配列の全要素を読む処理を拡張for文で書き、添字が必要になった時点で通常のfor文へ戻す考え方が扱いやすいです。

基本的な構文

基本構文では、左側に要素の型と変数名、右側に配列やコレクションを書きますし、これが一つの目安です。左側の型は、右側から取り出される要素の型と一致させますし、ここがポイントです。

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

結果: 構文のひな形であり、右側のデータから取り出した要素を左側の変数で扱う形になります。

int[]ならint numberString[]ならString textList<String>ならString valueのようにそろえますが、覚えておくと役立つでしょう。型が合わない場合はjavacのコンパイル時点でエラーになります。

Java基本文法の学習では、右側の要素型を先に読む習慣が役立ちますが、これは押さえたい点です。サンプルコードも、forの右側から左側へ視線を移すと構造を追いやすくなるのが目安です。

項目書き方向く場面注意点関連する語
配列の全件表示for (int n : numbers)全要素を読む添字は取れない拡張for文
文字列配列for (String s : names)文字列を順に処理null要素に注意Java基本文法
Listfor (String item : list)順序付きの要素処理削除は避けるプログラミング入門
Setfor (String tag : tags)重複なし集合順序は実装依存コーディングテクニック
二次元配列for (int[] row : matrix)行単位の走査内側のループが必要サンプルコード
条件分岐if (n % 2 == 0)条件に合う要素だけ処理条件を複雑にしすぎないプログラミング学習
途中終了break目的の値を見つけた時点で終了終了条件を明確にする制御構文
スキップcontinue特定要素を飛ばす読みづらい多用を避ける分岐
集計sum += n合計や件数の計算初期値を確認する変数
最大値探索max = Math.max(max, n)値の比較空配列の扱いが必要Math.max
メソッド呼び出しprint(item)処理を分ける副作用を確認するメソッド
独自クラスfor (Person p : people)オブジェクト配列getterの設計に注意class
ラムダ式list.forEach(x -> ...)短い処理複雑な処理は読みにくいforEach
削除処理Iterator反復中に削除removeを使うIterator
添字が必要for (int i = 0; ...)番号付き処理境界条件に注意length
配列長array.length通常for文メソッドではないlength
Listサイズlist.size()通常for文メソッド呼び出しsize()
標準出力System.out.println学習用の確認業務ログとは分けるSystem.out
文字数text.length()文字列処理文字単位の意味に注意String
例外処理try/catch失敗に備える広すぎる捕捉を避けるException
null対策if (x != null)null要素の確認呼び出し前に判定null
型推論var型が明白な場面読みやすさを優先var
final変数final String name再代入を避ける要素自体の不変ではないfinal
MapentrySet()キーと値の走査Entry型を読むMap.Entry
Streamstream()変換や絞り込み副作用を減らすStream
配列変換Arrays.asList簡単なリスト化固定サイズの性質に注意Arrays
空判定isEmpty()処理前チェックnullとは別isEmpty
ネストforの中にfor表形式データ深くしすぎない二重ループ
可読性短い変数名を避けるチーム開発意味のある名前にする命名
学習順配列からListへ進むプログラミング学習構文と用途を分けるプログラミング入門

早見表では、サンプルコードで頻出する形と注意点をまとめています。対象がarrayCollectionかで周辺の書き方は変わります。

Java List型完全ガイドを併読すると、Listと拡張for文の関係を整理できるのがポイントです。配列だけでなくコレクションまで扱うと、Java基本文法の理解が深まりますし、これが一つの目安です。

拡張for文の使い方

拡張for文の使い方は配列から始めると理解しやすいです。String[]int[]は要素の型と個数が明確で、プログラミング入門の教材にもよく登場します。

サンプルコード1:基本的な使い方

文字列配列を作り、各要素をSystem.out.printlnで表示する形が最小のサンプルコードです。変数fruitは、配列fruitsの要素を順番に受け取りますし、ここを基本と考えるとよいでしょう。

public class EnhancedForExample {
    public static void main(String[] args) {
        String[] fruits = {"りんご", "みかん", "ぶどう"};

        for (String fruit : fruits) {
            System.out.println(fruit);
        }
    }
}

結果: 期待される出力は、りんごみかんぶどうがこの順番で行ごとに表示される形です。

String[]の要素型はStringなので、ループ変数もString fruitになります。ループ内ではfruit.length()のようなStringのメソッドも呼び出せます。

ループ変数へ別の文字列を代入しても、配列そのものの要素は置き換わりません。要素の値や参照を受け取って処理する構文です。

サンプルコード2:配列との組み合わせ

配列との組み合わせでは、数値の合計や平均の計算にも拡張for文を使えるのが一般的です。読み取り専用の集計なら、添字を持たないことが意図の明確さにつながりますが、覚えておくと役立つでしょう。

public class ArraySumExample {
    public static void main(String[] args) {
        int[] scores = {80, 90, 75, 100};
        int total = 0;

        for (int score : scores) {
            total += score;
        }

        System.out.println("合計: " + total);
    }
}

結果: 期待される出力は合計: 345です。

このサンプルコードでは、totalに各scoreを足し込みます。scores[0]のような添字表現がないため、全件を足す処理だと読み取れます。

偶数番目だけ処理する、前後の要素を比較する、表示番号を付ける要件では添字が必要です。その場合はfor (int i = 0; i < scores.length; i++)へ切り替えますし、ここがポイントです。

サンプルコード3:コレクションとの組み合わせ

コレクションでは、ArrayListList型の変数で受ける書き方がよく使われますし、ここを基本と考えるとよいでしょう。java.util.Listの詳細はJava SE 21 APIのListで確認できます。

import java.util.ArrayList;
import java.util.List;

public class EnhancedForWithCollection {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("りんご");
        fruits.add("バナナ");
        fruits.add("ぶどう");

        for (String fruit : fruits) {
            System.out.println(fruit);
        }
    }
}

結果: 期待される出力は、りんごバナナぶどうが追加した順番で行ごとに表示される形です。

ArrayListは追加順を保持するため、出力も追加順になります。HashSetのような集合では順序が保証されず、同じ拡張for文でも表示順の意味が変わります。

順序に意味がある処理ではList、重複を避ける処理ではSetのように選びますが、これは押さえたい点です。これは拡張for文ではなく、データ構造を選ぶコーディングテクニックです。

ℹ️ 補足: Listの基本を先に固めたい場合は、本文中の内部リンクから関連するJava記事へ進むと、プログラミング学習の流れを崩さず確認できるのがポイントです。

Javaエスケープ処理のガイドでは、文字列を扱う際のn"の考え方を確認できます。文字列配列を出力するサンプルコードにも役立ちますし、これが一つの目安です。

拡張for文の応用例

拡張for文に慣れたら、二次元配列、条件分岐、メソッド呼び出しへ広げると実用に近づきます。単純な表示から処理の分割へ進むことで、Java基本文法が部品としてつながりますし、ここがポイントです。

サンプルコード4:ネストされた拡張for文

二次元配列は「配列の中に配列がある」構造です。外側の拡張for文で行を取り出し、内側の拡張for文で行の中の値を取り出するのが現実的です。

public class NestedEnhancedForExample {
    public static void main(String[] args) {
        int[][] matrix = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };

        for (int[] row : matrix) {
            for (int element : row) {
                System.out.print(element + " ");
            }
            System.out.println();
        }
    }
}

結果: 期待される出力は、1 2 34 5 67 8 9が行ごとに表示される形です。

rowの型はint[]で、elementの型はintです。外側と内側で型が変わる点を読むと、二重ループの意味を追いやすくなります。

ネストが深くなるほど読み手の負担は増えます。三重以上のループでは、メソッドへの切り出し、データ構造の見直し、Streamの利用も検討すると整理できるのが一般的です。

サンプルコード5:条件分岐との組み合わせ

条件分岐と組み合わせると、全要素を読みながら条件に合うものだけ処理できます。整数配列から偶数だけを出力する処理では、%演算子で割り切れるかを判定します。

public class ExtendedForWithConditional {
    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 4, 5, 6};

        for (int number : numbers) {
            if (number % 2 != 0) {
                continue;
            }
            System.out.println(number + "は偶数です");
        }
    }
}

結果: 期待される出力は、2は偶数です4は偶数です6は偶数ですが行ごとに表示される形です。

この例では、奇数のときにcontinueで残りの処理を飛ばします。条件に合わない要素を早めに除外すると、出力処理の条件が読みやすくなります。

条件が何層にも重なる場合は、isEven(number)のような判定メソッドを作ると扱いやすくなると理解できるのが現実的です。プログラミング学習では、長いifを短い名前付きメソッドへ分ける考え方も重要です。

サンプルコード6:メソッドとの組み合わせ

メソッドと組み合わせると、ループの役割を「要素を渡すこと」に絞れます。表示や計算の詳細は別メソッドへ移すため、拡張for文の中身が短くなります。

public class MethodExample {
    public static void main(String[] args) {
        String[] fruits = {"りんご", "バナナ", "ぶどう"};

        for (String fruit : fruits) {
            printFruitDetails(fruit);
        }
    }

    private static void printFruitDetails(String fruit) {
        System.out.println("名前: " + fruit);
        System.out.println("文字数: " + fruit.length());
    }
}

結果: 期待される出力は、各フルーツ名とlength()で得られる文字数が交互に表示される形です。

このサンプルコードでは、printFruitDetailsが一つのStringを受け取り、名前と文字数を表示します。拡張for文は配列の各要素を順に渡すだけです。

同じ処理を別の配列やListにも使いたい場合、メソッド化が有効です。単なる短縮ではなく、コーディングテクニックとして再利用の単位を作る作業です。

Javaのオーバーライド解説を読むと、メソッド名、引数、戻り値の考え方を広げられます。拡張for文から呼ぶメソッドの設計にもつながりますが、覚えておくと役立つでしょう。

拡張for文の詳細な注意点

拡張for文は読みやすい反復処理を書けますが、すべてのループを置き換える構文ではありません。特に、例外、要素の削除、添字、性能の見方は押さえる必要があると整理できます。

例外処理の取り扱い

拡張for文自体は、配列の範囲外へ添字アクセスする構文ではありません。for (int value : array)で読むだけなら、添字ミスによるArrayIndexOutOfBoundsExceptionは起きにくくなります。

ただし、ループ内で別の配列へ添字アクセスしたり、null要素に対してメソッドを呼んだりすれば例外は発生すると覚えるとよいでしょう。拡張for文は例外を消すのではなく、添字管理の一部を不要にします。

public class ExceptionExample {
    public static void main(String[] args) {
        String[] names = {"田中", null, "佐藤"};

        for (String name : names) {
            if (name == null) {
                System.out.println("名前が未設定です");
                continue;
            }
            System.out.println(name.length());
        }
    }
}

結果: 期待される出力は、2名前が未設定です2が行ごとに表示される形です。

このコードでは、name == nullを先に判定してからlength()を呼び出します。つまずきやすい点は構文ではなく、ループ内で扱う値の状態です。

公式ドキュメントによれば、NullPointerExceptionnull参照に対してインスタンスメソッドを呼ぶ場合などに発生します。詳細はJava SE 21 APIのNullPointerExceptionが一次情報です。

要素の削除とConcurrentModificationException

拡張for文でListを回している最中に、同じListから直接removeすると、ConcurrentModificationExceptionが起きる場合があります。反復中の構造変更は慎重に扱います。

⚠️ 注意: 拡張for文の中でlist.remove(item)を直接呼ぶ書き方は避けますし、ここを基本と考えるとよいでしょう。削除が必要な場合はIteratorremove()、またはremoveIfを検討すると覚えるとよいでしょう。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class IteratorRemoveExample {
    public static void main(String[] args) {
        List<String> names = new ArrayList<>();
        names.add("田中");
        names.add("未設定");
        names.add("佐藤");

        Iterator<String> iterator = names.iterator();
        while (iterator.hasNext()) {
            String name = iterator.next();
            if (name.equals("未設定")) {
                iterator.remove();
            }
        }

        System.out.println(names);
    }
}

結果: 期待される出力は[田中, 佐藤]です。

この例では、削除が必要なため拡張for文ではなくIteratorを使っています。読み取り中心なら拡張for文、反復中に安全に削除したいならIteratorが一般的です。

条件に合う要素をまとめて消すだけなら、removeIfも候補です。短い条件ならnames.removeIf(name -> name.equals("未設定"))のように書けます。

パフォーマンスに関する注意

性能については、拡張for文が常に遅い、または常に速いとは言えません。配列では添字ベースのループに近い形、コレクションでは通常Iteratorを介した反復になると考えられますが、これは押さえたい点です。

短い確認コードは、JITコンパイル、ウォームアップ、最適化、実行環境の影響を受けます。学習用のサンプルコードだけで速度の優劣を断定するのは避けます。

import java.util.List;

public class LoopChoiceExample {
    public static void main(String[] args) {
        List<String> names = List.of("田中", "佐藤", "鈴木");

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

結果: 期待される出力は、田中佐藤鈴木が行ごとに表示される形です。

この程度の処理では、可読性を優先して拡張for文を選ぶ判断が自然です。性能差が問題になるのは、大量データや処理時間の制約が明確な箇所に限られます。

読みやすい拡張for文を基本にし、添字アクセスが必要な箇所だけ通常のfor文にする書き分けが実用的です。プログラミング入門から実務寄りのプログラミング学習へ進む際にも役立ちます。

拡張for文のカスタマイズ方法

拡張for文の対象は、プリミティブ配列や文字列リストだけではありません。独自クラスの配列、List<Person>Map.Entry、ラムダ式を使ったforEachにも広げられますし、ここがポイントです。

サンプルコード7:カスタムクラスの利用

独自クラスを配列に入れると、拡張for文でオブジェクトを一件ずつ取り出せますし、これが一つの目安です。Personクラスにnameageを持たせ、配列として扱う形です。

public class Main {
    public static void main(String[] args) {
        Person[] people = {
            new Person("田中", 30),
            new Person("佐藤", 25),
            new Person("鈴木", 35)
        };

        for (Person person : people) {
            System.out.println(person.getName() + "さんは" + person.getAge() + "歳です");
        }
    }
}

class Person {
    private final String name;
    private final int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    String getName() {
        return name;
    }

    int getAge() {
        return age;
    }
}

結果: 期待される出力は、田中さんは30歳です佐藤さんは25歳です鈴木さんは35歳ですが行ごとに表示される形です。

Personのフィールドはprivate finalで、値の取得はgetName()getAge()に任せています。拡張for文はPersonオブジェクトを順に受け取り、必要なメソッドを呼びます。

クラス設計が複雑になるほど、ループ内に処理を書き込みすぎると読みにくくなると言えるでしょう。表示用の文字列をtoDisplayText()のようなメソッドへ寄せると、コーディングテクニックとして責任範囲を分けられますが、覚えておくと役立つでしょう。

Mapのキーと値を扱う

Mapでは、entrySet()Map.Entryを取り出す形がよく使われます。キーと値を同時に使いたいときに向いた書き方です。

import java.util.LinkedHashMap;
import java.util.Map;

public class MapEntryExample {
    public static void main(String[] args) {
        Map<String, Integer> scores = new LinkedHashMap<>();
        scores.put("田中", 80);
        scores.put("佐藤", 90);
        scores.put("鈴木", 75);

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

結果: 期待される出力は、田中: 80佐藤: 90鈴木: 75が行ごとに表示される形です。

この例では、追加順を保つためにLinkedHashMapを使っています。HashMapでは順序に依存しない処理にする必要があります。

Javaアノテーションの解説では、クラスやメソッドへメタ情報を付ける考え方を確認できるのが基本です。独自クラスを扱うプログラミング学習では、文法同士のつながりも重要です。

サンプルコード8:ラムダ式との組み合わせ

Java 8以降では、forEachとラムダ式で各要素を処理する書き方も使えると理解できます。拡張for文そのものではありませんが、各要素に処理を適用する場面で比較されます。

import java.util.List;

public class ForEachLambdaExample {
    public static void main(String[] args) {
        List<String> items = List.of("apple", "banana", "cherry");

        items.forEach(item -> System.out.println(item));
    }
}

結果: 期待される出力は、applebananacherryが行ごとに表示される形です。

item -> System.out.println(item)が各要素への処理を表します。短い出力や単純な変換には向きますが、breakcontinueは拡張for文と同じ感覚では使えません。

途中で抜けたい、例外処理を細かく書きたい、複数行の条件分岐がある場合は拡張for文が扱いやすいことがあります。短さだけでなく、制御の明確さで選びますが、これは押さえたい点です。

⚠️ 注意: ラムダ式は短い処理に合いますが、複雑な分岐を詰め込むと読み取りづらくなるのが目安です。複数行に広がるなら、拡張for文やメソッド分割を検討すると覚えるとよいでしょう。

Javaでうるう年を判定する記事のような条件分岐中心の例も参考になります。条件を小さく名前付きにする考え方は、ラムダ式でも拡張for文でも共通するのが目安です。

まとめ

拡張for文は、配列やコレクションの全要素を順に読む処理に向いたJava基本文法です。for (String item : items)の形にすると、要素を一件ずつ処理する意図が短く伝わります。

添字が必要な処理、反復中の削除、途中終了を細かく制御する処理では、通常のfor文やIteratorが適する場合があると考えられます。構文の短さだけでなく、処理の目的に合わせて選びますし、これが一つの目安です。

プログラミング入門では、配列の表示、合計、条件分岐、メソッド呼び出しの順にサンプルコードを写すと使いどころをつかみやすくなります。プログラミング学習では、同じ処理を通常のfor文でも書き比べると違いが見えます。

拡張for文は「要素を読む」ための構文であり、「場所を操作する」構文ではありません。この違いを覚えると、ListMap、ラムダ式へ進んだときも判断しやすくなるのがポイントです。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。