【Java学習|初心者向け】Javaのリスト操作でハマる「ConcurrentModificationException」を回避するIterator.remove()の使い方

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などのモダンな記述を覚えていくと、より堅牢なプログラムが書けるようになりますよ。

コメント

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