振る舞いパターン
コレクションの内部構造を公開せずに、要素を順番にアクセスする方法を提供する。
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() + " ");
}
// 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();
以下の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)
);
【追加機能】
・スキップ件数の取得
・マッチ件数のカウント