1. 導入:なぜコレクションの削除処理が重要なのか
Javaの開発現場において、ListやSetから要素を削除する処理は日常的です。しかし、ループ処理中に不用意にremoveメソッドを呼び出すと、ConcurrentModificationExceptionが発生し、システムが停止するリスクがあります。本記事では、コレクション操作における「安全な削除」と「効率的な削除」のベストプラクティスを解説します。
2. 基礎知識:Javaコレクションの削除メソッド
JavaのCollectionインターフェースには、主に以下の2つの削除メソッドが存在します。
・remove(Object o): 指定された要素の最初の出現を削除します。
・removeAll(Collection> c): 指定されたコレクションに含まれる要素をすべて削除します。
これらのメソッドは、内部的に「イテレータ」を使用して要素を走査します。そのため、拡張for文(for-eachループ)の中で直接これらのメソッドを呼び出すと、イテレータの整合性が崩れ、例外が投げられる仕様になっています。
3. 実装/解決策:安全な削除方法
実務において最も推奨されるのは、Java 8から導入されたremoveIf(Predicate filter)メソッドを使用することです。これにより、ループを自前で書く必要がなくなり、コードの可読性と安全性が劇的に向上します。
4. サンプルプログラム
以下に、Listから条件に一致する要素を安全に削除する実用的なコード例を示します。
import java.util.ArrayList;
import java.util.List;
public class CollectionRemoveExample {
public static void main(String[] args) {
List
items.add(“Apple”);
items.add(“Banana”);
items.add(“Cherry”);
items.add(“Date”);
// 1. removeIfを使った安全な削除(推奨)
// 「B」で始まる要素をすべて削除する
items.removeIf(item -> item.startsWith(“B”));
// 2. removeAllを使った一括削除
// 削除対象のリストを定義
List
items.removeAll(toRemove);
// 結果を出力:Cherryのみが残る
items.forEach(System.out::println);
}
}
5. 応用・注意点:現場での落とし穴
現場で遭遇しやすい注意点を3つ挙げます。
・Arrays.asList()の罠: Arrays.asList()で作成したリストは固定サイズであるため、removeメソッドを呼ぶとUnsupportedOperationExceptionが発生します。変更が必要な場合は、new ArrayList<>(Arrays.asList(…))のようにラップしてください。
・Mapの削除: Map自体にはremoveIfはありませんが、entrySet()を取得してそのイテレータを操作するか、keySet().removeIf()を使用することで安全に削除可能です。
・Sequenced Collections (Java 21以降): Java 21から導入されたSequencedCollectionでは、first/last要素の削除がより直感的になりました。順序が重要なリストを扱う際は、これらの新しいAPIを検討しましょう。
パフォーマンス面では、ArrayListに対して頻繁にremoveを行うと、後ろの要素を詰めるためのコピー処理が走り、計算量がO(n)になります。削除対象が多い場合は、一度で削除するのではなく「新しいリストを作成する(フィルタリング)」というアプローチも検討してください。

コメント