1. 導入:なぜIteratorでの削除が必要なのか?
Javaでリスト(List)をループさせながら要素を削除しようとした経験はありますか?多くの初心者が、拡張for文の中で「list.remove()」を呼び出して「ConcurrentModificationException(同時変更例外)」に遭遇します。このエラーは、ループの最中にリストの構造を直接変更しようとした時に発生します。Iteratorを使うと、安全かつスマートに要素を削除できるため、この手法をマスターすることはJavaプログラミングの第一歩です。
2. 基礎知識:Iteratorとは何か
Iterator(イテレータ)とは、コレクションの中身を順番にたどるための「カーソル」のような仕組みです。
Javaのコレクション(ListやSetなど)は「Iterable」インターフェースを実装しており、「iterator()」メソッドを呼ぶことで、そのコレクション専用のIteratorを取得できます。
Iteratorには、主に以下の2つの役割があります。
・hasNext(): 次の要素が存在するか確認する。
・next(): 次の要素を取得し、カーソルを一つ進める。
ここに「remove()」という強力な武器が加わることで、反復処理中の安全な削除が可能になります。
3. 実装/解決策:正しい削除の手順
ループ中に要素を削除する際の鉄則は、「リストのメソッドを直接呼ぶのではなく、Iteratorのremove()メソッドを呼ぶ」ことです。Iterator経由で削除することで、Java内部でリストのインデックス整合性が保たれ、例外を回避できます。
4. サンプルプログラム
以下のコードをコピーして動作を確認してみてください。リストから偶数の数値を安全に削除する例です。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Main {
public static void main(String[] args) {
// テスト用リストの作成
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
// Iteratorを取得
Iterator<Integer> iterator = numbers.iterator();
// hasNextで要素がある限り繰り返す
while (iterator.hasNext()) {
Integer num = iterator.next();
// 偶数だったら削除する
if (num % 2 == 0) {
// リストのremoveではなく、iteratorのremoveを呼び出すのがポイント
iterator.remove();
}
}
// 結果を出力:[1, 3] と表示される
System.out.println("削除後のリスト: " + numbers);
}
}
5. 応用・注意点:現場でのテクニック
現場の開発では、Java 8以降であれば「removeIf」というさらに便利なメソッドが好まれます。
例えば「numbers.removeIf(n -> n % 2 == 0);」と一行書くだけで、上記と同じ処理が実現可能です。
ただし、以下の点に注意してください。
・remove()の連続呼び出しは不可: next()を呼ばずにremove()を2回連続で呼ぶと「IllegalStateException」が発生します。
・拡張for文の罠: 「for (Integer n : numbers)」のような拡張for文は内部でIteratorを使っていますが、直接remove()を呼ぶと例外になります。複雑な条件分岐で削除を行いたい場合は、あえて明示的にIteratorを使うのが最も確実でバグを防ぎやすい書き方です。
まずはIteratorの動きを理解し、その後に便利なremoveIfなどのモダンな記述を覚えていくと、より堅牢なプログラムが書けるようになりますよ。

コメント