この内容は古いバージョンです。最新バージョンを表示するには、戻るボタンを押してください。
バージョン:8
ページ更新者:T
更新日時:2026-06-11 07:12:00

タイトル: 拡張for文
SEOタイトル: Java 拡張 for 文 (for-each) 完全ガイド

この記事の要点
  • 拡張 for 文 (for-each) = for (E item : collection) { ... } 構文。Java 5 (2004) から導入
  • 配列 / Collection (List/Set) / Iterable を実装した任意のオブジェクトを反復可能
  • 内部的には Iterator を使った変換 — 配列は単純な index ループに展開される
  • Map の反復は entrySet()/keySet()/values() 経由
  • index が必要または反復中に要素削除したい場合は通常 for や Iterator を直接使う

拡張 for 文 (for-each) の基本構文

// 構文: for (要素の型 変数 : 反復対象)
int[] nums = {1, 2, 3, 4, 5};
for (int n : nums) {
    System.out.println(n);
}

// List
List<String> names = List.of("Alice", "Bob", "Carol");
for (String name : names) {
    System.out.println(name);
}

// Set
Set<Integer> ids = Set.of(1, 2, 3);
for (int id : ids) {
    System.out.println(id);
}

通常 for 文との比較

項目通常 for拡張 for
index 取得可能 (i)不可
反復中の要素削除可能不可 (ConcurrentModificationException)
逆順反復可能不可 (リストの reverse 必要)
記述量多い少ない
可読性普通高い
速度同等同等 (コンパイル後ほぼ同じ)
// 通常 for (index が必要なとき)
for (int i = 0; i < names.size(); i++) {
    System.out.println(i + ": " + names.get(i));
}

// 拡張 for (シンプルに反復)
for (String name : names) {
    System.out.println(name);
}

// 拡張 for + index が欲しい場合は自分でカウンタ
int i = 0;
for (String name : names) {
    System.out.println(i + ": " + name);
    i++;
}

Iterable インターフェース

拡張 for 文は配列java.lang.Iterableを実装した任意のクラスで使えます。自作クラスを反復可能にするには Iterable を実装するだけで OK。

import java.util.Iterator;

// 自作 Iterable
public class Range implements Iterable<Integer> {
    private final int start, end;
    public Range(int start, int end) { this.start = start; this.end = end; }

    @Override
    public Iterator<Integer> iterator() {
        return new Iterator<>() {
            int current = start;
            public boolean hasNext() { return current < end; }
            public Integer next() { return current++; }
        };
    }
}

// 使う
for (int i : new Range(1, 5)) {
    System.out.println(i);   // 1, 2, 3, 4
}

Map の反復

Map は Iterable を直接実装していないので、entrySet() / keySet() / values() を経由します。

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

// 1. entrySet (★ 推奨: key と value 両方使う場合)
for (Map.Entry<String, Integer> e : scores.entrySet()) {
    System.out.println(e.getKey() + " = " + e.getValue());
}

// 2. keySet (key のみ)
for (String key : scores.keySet()) {
    System.out.println(key);
}

// 3. values (value のみ)
for (int v : scores.values()) {
    System.out.println(v);
}

// 4. Java 8+ forEach + Lambda
scores.forEach((k, v) -> System.out.println(k + " = " + v));

break / continue は使える

for (String name : names) {
    if (name.equals(&quot;Bob&quot;)) {
        continue;       // この回をスキップ
    }
    if (name.equals(&quot;END&quot;)) {
        break;          // ループ脱出
    }
    System.out.println(name);
}

// ラベル付き break で多重ループ脱出
outer:
for (int[] row : matrix) {
    for (int n : row) {
        if (n == 0) break outer;     // ★ outer ループも脱出
    }
}

反復中の要素削除は不可

拡張 for 文の中で Collection の要素を削除すると ConcurrentModificationException が出ます。Iterator を直接使うか、別の方法を取ります。

List<String> list = new ArrayList<>(List.of("a", "b", "c"));

// NG ConcurrentModificationException
for (String s : list) {
    if (s.equals("b")) list.remove(s);
}

// OK1: Iterator.remove
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("b")) it.remove();
}

// OK2: Collection.removeIf (Java 8+)
list.removeIf(s -> s.equals("b"));

// OK3: Stream + collect で新 List
list = list.stream()
    .filter(s -> !s.equals("b"))
    .collect(Collectors.toList());

Java 8+ Stream.forEach との違い

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

// 拡張 for (順次)
for (int n : nums) {
    System.out.println(n);
}

// Stream.forEach (順次)
nums.forEach(System.out::println);

// Stream の真価: フィルタ + マップ + 集計
int sum = nums.stream()
    .filter(n -> n % 2 == 0)         // 偶数のみ
    .mapToInt(Integer::intValue)
    .sum();

// ★ parallelStream で並列処理 (順序保証なし)
nums.parallelStream().forEach(System.out::println);

使い分けチートシート

ケース推奨
単純に全要素を 1 回ずつ処理拡張 for
index が欲しい通常 for
反復中に要素を削除Iterator or removeIf
逆順通常 for (i 降順) or Collections.reverse
フィルタ + 集計Stream
並列処理parallelStream
Map 反復entrySet() + 拡張 for or forEach

FAQ

Q: 拡張 for と通常 for どちらが速い?
A: ArrayList では同等。LinkedList では拡張 for (Iterator) のほうが速い (通常 for で get(i) すると O(n) 検索が毎回走る)。

Q: 配列の中身を変更できる?
A: プリミティブ配列ならループ変数を変えても配列本体は変わらない。参照型なら参照先のフィールドは変更可能。要素差し替えには index ベース for を使う。

Q: 拡張 for で null チェックは?
A: 反復対象自体が null だと NPE。事前に if (list != null)Objects.requireNonNullElse(list, List.of())