0Pricing
Java Academy · レッスン

Iterable と Iterator の契約

Iterable と Iterator のインターフェース、および for-each ループが内部で動作する仕組みを理解します。

「Iterable と Iterator の契約」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

IterableとIterator

Iterable<T>とIterator<T>は、Javaのfor-eachループを支えるインターフェースです。これらを理解すると、独自のデータ構造をループで扱えるようにできます。

Iterableインターフェース

Iterable<T>には、Iterator<T>を返すiterator()という1つのメソッドがあります。Iterableを実装するクラスは、for-eachループで使用できます。

// java.lang.Iterable<T>
interface Iterable<T> {
    Iterator<T> iterator();
    // default: forEach, spliterator (Java 8+)
}

// Any class implementing Iterable<T> works in for-each:
class Range implements Iterable<Integer> {
    private final int start, end;
    Range(int start, int end) { this.start = start; this.end = end; }

    public Iterator<Integer> iterator() {
        return new RangeIterator(); // defined separately
    }
}

Iteratorインターフェース

Iterator<T>には、hasNext()、next()、そして任意実装のremove()という3つのメソッドがあります。

// java.util.Iterator<T>
interface Iterator<T> {
    boolean hasNext(); // true if more elements
    T next();          // returns next element, advances cursor
    default void remove() { throw new UnsupportedOperationException(); }
}

// How for-each desugars internally:
// for (T item : iterable) { use(item); }
// becomes:
Iterator<T> it = iterable.iterator();
while (it.hasNext()) {
    T item = it.next();
    // use(item)
}

For-Eachループの糖衣構文

For-eachループは、Iterable/Iteratorパターンに対する糖衣構文です。これを理解すると、カスタムIterableを正しく記述できるようになります。

List<String> names = List.of("Alice", "Bob", "Charlie");

// For-each (readable way)
for (String name : names) {
    System.out.println(name);
}

// Equivalent explicit form
Iterator<String> it = names.iterator();
while (it.hasNext()) {
    String name = it.next();
    System.out.println(name);
}

Iteratorのカーソル状態

Iteratorはカーソル、つまりシーケンス内の位置を保持します。next()を呼び出すとカーソルが先に進みます。すべての要素を処理し終えると、iteratorをリセットすることはできません。

List<Integer> nums = List.of(1, 2, 3);
Iterator<Integer> it = nums.iterator();

System.out.println(it.hasNext()); // true
System.out.println(it.next());    // 1
System.out.println(it.next());    // 2
System.out.println(it.next());    // 3
System.out.println(it.hasNext()); // false

try {
    it.next(); // NoSuchElementException
} catch (java.util.NoSuchElementException e) {
    System.out.println("No more elements!");
}

ConcurrentModificationException

明示的なiteratorで反復処理している途中に、Iterator.remove()以外の方法でコレクションを変更すると、ConcurrentModificationExceptionがスローされます。

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

// BAD: modifying collection during for-each
try {
    for (String s : list) {
        if ("b".equals(s)) list.remove(s); // ConcurrentModificationException!
    }
} catch (java.util.ConcurrentModificationException e) {
    System.out.println("Cannot modify during iteration!");
}

// GOOD: use Iterator.remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if ("b".equals(it.next())) it.remove(); // safe
}
System.out.println(list); // [a, c, d]

複数のIterator

iterator()を呼び出すたびに、新しく独立したiteratorが返されます。同じコレクションに対して、複数のiteratorを同時に使用できます。

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

Iterator<Integer> a = nums.iterator();
Iterator<Integer> b = nums.iterator();

System.out.println(a.next()); // 1
System.out.println(b.next()); // 1 (independent cursor)
System.out.println(a.next()); // 2
System.out.println(b.next()); // 2

IterableとIteratorの比較

重要な違い:

  • Iterable:iteratorを生成できるデータソース。複数回反復処理できます
  • Iterator:シーケンス上のカーソル。1回だけ使用する状態保持型です
// Iterable: reusable
List<String> list = List.of("x", "y");
for (String s : list) {} // OK
for (String s : list) {} // OK again — new iterator each time

// Iterator: single-use
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
// for (String s : it) {} // compile error — Iterator is not Iterable!

実践:カスタムファイル行Iterable

ファイルを読み込み、その行をfor-eachループで処理できるようにIterableを実装したリーダーです。

import java.io.*;
import java.util.*;

class FileLines implements Iterable<String>, Closeable {
    private final BufferedReader reader;

    FileLines(String path) throws IOException {
        this.reader = new BufferedReader(new FileReader(path));
    }

    public Iterator<String> iterator() {
        return new Iterator<>() {
            private String nextLine = readNext();

            private String readNext() {
                try { return reader.readLine(); }
                catch (IOException e) { return null; }
            }

            public boolean hasNext() { return nextLine != null; }
            public String next() {
                String curr = nextLine;
                nextLine = readNext();
                return curr;
            }
        };
    }

    public void close() throws IOException { reader.close(); }
}

forEachのデフォルトメソッド

Java 8では、IterableにデフォルトのforEach(Consumer)メソッドが追加されました。明示的なループを記述する代わりに便利に使えます。

List<String> cities = List.of("New York", "London", "Tokyo");

// for-each loop
for (String city : cities) System.out.println(city);

// forEach with lambda
cities.forEach(city -> System.out.println(city));

// forEach with method reference (most concise)
cities.forEach(System.out::println);

// For transforming: use stream
cities.stream()
    .map(String::toUpperCase)
    .forEach(System.out::println);

実践でのIteratorパターン

Iterable/Iteratorを実装する場面のまとめ:

  • カスタムデータ構造(木、グラフ、連結リスト)
  • 必要に応じて要素を生成する遅延シーケンス
  • リソースベースのシーケンス(ファイルの行、DBカーソル、メッセージキュー)

クイックチェック

for-eachループで反復処理している途中にコレクションを変更すると、どの例外がスローされますか。

まとめ:IterableとIteratorの契約

重要なポイント:

  • Iterableにはiterator()という1つのメソッドがあり、for-eachループをサポートできます
  • IteratorにはhasNext()、next()、そして任意実装のremove()があります
  • For-eachループは、Iterable/Iteratorパターンに対する糖衣構文です
  • iterator()を複数回呼び出すと、独立した新しいカーソルを取得できます
  • for-eachの実行中はコレクションを変更せず、代わりにIterator.remove()を使用してください
  • カスタムデータ構造でfor-eachループをサポートするには、Iterableを実装します

よくある質問

「Iterable と Iterator の契約」レッスンは無料ですか?

はい。「Iterable と Iterator の契約」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「Iterable と Iterator の契約」で何を学びますか?

Iterable と Iterator のインターフェース、および for-each ループが内部で動作する仕組みを理解します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「Iterable と Iterator の契約」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. Iterable と Iterator の契約
  2. カスタム Iterator の実装
  3. ListIterator と双方向走査
  4. Fail-Fast と Fail-Safe の Iterator
← Java Academyに戻る