【Java学習|実務向け】Iterator.hasNext()の正しい理解とJavaにおける反復処理の最適解

導入

Javaでの開発において、コレクション内の要素を操作する機会は非常に多いです。しかし、ループ処理の書き方を誤ると、コードの可読性が下がるだけでなく、意図しない例外(ConcurrentModificationExceptionなど)を招くリスクがあります。本稿では、Iteratorの根幹であるhasNext()メソッドの役割を整理し、現場で推奨されるループ処理の使い分けについて解説します。

基礎知識

Iteratorとは、コレクションの要素を順番に走査するためのインターフェースです。その主なメソッドは以下の通りです。
hasNext(): 次の要素が存在する場合にtrueを返します。
next(): 次の要素を返し、カーソルを1つ進めます。

これらは、コレクションの内部構造(ArrayListやHashSetなど)を意識せずに、統一的な方法でデータへアクセスするために設計されています。

実装/解決策

実務では、明示的にIteratorを使うケースは限られており、多くの場合「拡張for文(for-each)」が推奨されます。しかし、以下のようなケースではIteratorの直接操作が必要です。
1. 反復中に要素を削除したい場合
2. 複数のコレクションを同期して走査する場合

Iteratorを使う際の基本ルールは、「必ずhasNext()で存在確認を行ってからnext()を呼ぶ」ことです。これを怠るとNoSuchElementExceptionが発生します。

サンプルプログラム

以下のコードは、Iteratorを使用してリストから特定の条件(偶数)を満たす要素を安全に削除する例です。


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

public class IteratorSample {
public static void main(String[] args) {
List numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);

// Iteratorを取得
Iterator iterator = numbers.iterator();

// hasNext()で次の要素があるか確認し、安全にループを回す
while (iterator.hasNext()) {
Integer number = iterator.next();

// 偶数の場合は削除する
// for-each文で直接リストをremoveすると例外になるため、Iteratorのremoveを使用する
if (number % 2 == 0) {
iterator.remove();
}
}

System.out.println("処理後のリスト: " + numbers);
}
}

応用・注意点

現場で注意すべきポイントを3つ挙げます。

1. ConcurrentModificationExceptionの回避: 拡張for文を使用している最中に、そのコレクションに対してaddやremoveを行うとこの例外が発生します。要素の削除が必要な場合は、必ず上記サンプルのようにIterator.remove()を使用してください。

2. Iteratorの再利用不可: Iteratorは使い捨てのオブジェクトです。一度最後まで走査しきると、もう一度先頭から走査することはできません。再度ループしたい場合は、再度iterator()メソッドを呼び出す必要があります。

3. Stream APIとの使い分け: Java 8以降、集計やフィルタリングにはStream APIが推奨されます。単に要素を表示・検索するだけであれば、Iteratorを直接書くよりも、Stream APIや拡張for文の方がコードの意図が明確になります。

技術的な要件に合わせて、適切なループ手段を選択することが、保守性の高いコードを書く第一歩です。

コメント

タイトルとURLをコピーしました