← 一覧に戻る

Iterator

振る舞いパターン

コレクションの内部構造を公開せずに、要素を順番にアクセスする方法を提供する。

目次
  1. クラス図
  2. シーケンス図
  3. 使いどころ
  4. コード例
  5. AIプロンプト例
  6. 注意点
  7. 関連パターン

クラス図

シーケンス図

使いどころ

コード例

Java標準Iteratorの実装

public class PagedResultSet<T> implements Iterable<T> {
    private final int pageSize;
    private final DataFetcher<T> fetcher;

    public PagedResultSet(int pageSize, DataFetcher<T> fetcher) {
        this.pageSize = pageSize;
        this.fetcher = fetcher;
    }

    @Override
    public Iterator<T> iterator() {
        return new PagedIterator();
    }

    private class PagedIterator implements Iterator<T> {
        private int currentPage = 0;
        private List<T> currentBatch = new ArrayList<>();
        private int indexInBatch = 0;
        private boolean hasMorePages = true;

        @Override
        public boolean hasNext() {
            if (indexInBatch < currentBatch.size()) {
                return true;
            }
            if (!hasMorePages) {
                return false;
            }
            // 次のページを取得
            loadNextPage();
            return !currentBatch.isEmpty();
        }

        @Override
        public T next() {
            if (!hasNext()) {
                throw new NoSuchElementException();
            }
            return currentBatch.get(indexInBatch++);
        }

        private void loadNextPage() {
            currentBatch = fetcher.fetch(currentPage, pageSize);
            indexInBatch = 0;
            currentPage++;
            if (currentBatch.size() < pageSize) {
                hasMorePages = false;
            }
        }
    }
}

// 使用例
PagedResultSet<User> users = new PagedResultSet<>(100, userRepository::findAll);

for (User user : users) {
    // 内部で自動的にページングされる
    System.out.println(user.getName());
}

ツリー走査イテレータ

public class TreeNode<T> {
    private T value;
    private List<TreeNode<T>> children = new ArrayList<>();

    public TreeNode(T value) {
        this.value = value;
    }

    public void addChild(TreeNode<T> child) {
        children.add(child);
    }

    // 深さ優先イテレータ
    public Iterator<T> depthFirstIterator() {
        return new DepthFirstIterator();
    }

    // 幅優先イテレータ
    public Iterator<T> breadthFirstIterator() {
        return new BreadthFirstIterator();
    }

    private class DepthFirstIterator implements Iterator<T> {
        private Deque<TreeNode<T>> stack = new ArrayDeque<>();

        DepthFirstIterator() {
            stack.push(TreeNode.this);
        }

        @Override
        public boolean hasNext() {
            return !stack.isEmpty();
        }

        @Override
        public T next() {
            TreeNode<T> node = stack.pop();
            // 子ノードを逆順でスタックに追加
            for (int i = node.children.size() - 1; i >= 0; i--) {
                stack.push(node.children.get(i));
            }
            return node.value;
        }
    }

    private class BreadthFirstIterator implements Iterator<T> {
        private Queue<TreeNode<T>> queue = new LinkedList<>();

        BreadthFirstIterator() {
            queue.offer(TreeNode.this);
        }

        @Override
        public boolean hasNext() {
            return !queue.isEmpty();
        }

        @Override
        public T next() {
            TreeNode<T> node = queue.poll();
            queue.addAll(node.children);
            return node.value;
        }
    }
}

使用例

// ツリー構造
TreeNode<String> root = new TreeNode<>("root");
TreeNode<String> a = new TreeNode<>("A");
TreeNode<String> b = new TreeNode<>("B");
root.addChild(a);
root.addChild(b);
a.addChild(new TreeNode<>("A1"));
a.addChild(new TreeNode<>("A2"));

// 深さ優先: root → A → A1 → A2 → B
Iterator<String> dfs = root.depthFirstIterator();
while (dfs.hasNext()) {
    System.out.print(dfs.next() + " ");
}

// 幅優先: root → A → B → A1 → A2
Iterator<String> bfs = root.breadthFirstIterator();
while (bfs.hasNext()) {
    System.out.print(bfs.next() + " ");
}

Stream APIとの連携

// IteratorからStreamを生成
public static <T> Stream<T> toStream(Iterator<T> iterator) {
    Spliterator<T> spliterator = Spliterators.spliteratorUnknownSize(
        iterator, Spliterator.ORDERED
    );
    return StreamSupport.stream(spliterator, false);
}

// 使用例
PagedResultSet<User> users = new PagedResultSet<>(100, userRepository::findAll);

long count = toStream(users.iterator())
    .filter(u -> u.getAge() >= 20)
    .count();

AIプロンプト例

カスタマイズ用プロンプト

以下のIteratorパターンを作成してください。

【用途】
外部APIからの大量データ取得

【要件】
・1回のAPI呼び出しで最大1000件取得
・カーソルベースのページネーション
・リトライ機能(3回まで)
・レート制限対応(1秒間隔)

【インターフェース】
ApiResultIterator<T> implements Iterator<T>

【コンストラクタ引数】
・apiClient: APIクライアント
・endpoint: エンドポイントURL
・queryParams: クエリパラメータ

【追加メソッド】
・getTotalCount(): int - 全件数
・getCurrentPage(): int - 現在ページ
・close(): void - リソース解放

フィルタリングイテレータ用プロンプト

フィルタリング機能付きIteratorを作成してください。

【用途】
ログファイルの解析

【FilteringIterator】
・元のIteratorをラップ
・Predicate<T>で条件指定
・複数条件のAND/OR結合

【使用例】
Iterator<LogEntry> filtered = new FilteringIterator<>(
    logIterator,
    entry -> entry.getLevel() == Level.ERROR,
    entry -> entry.getTimestamp().isAfter(yesterday)
);

【追加機能】
・スキップ件数の取得
・マッチ件数のカウント

注意点

← 一覧に戻る