ルール
使用 安全な メソッド するときは 除去 コレクションから
変更 a コレクション コレクションの コレクション しばしば バグを バグを引き起こす。
サポート言語: PY、 Java、 C/C++、 C#、
Swift/Objective-C, Ruby, PHP、 Kotlin, Go,
Scala、 Rust、 Groovy, Dart, Julia, Elixit、
Erlang, Clojure、 OCaml、 Luaはじめに
イテレーション中にコレクションから項目を削除すると、Javaでは並行変更例外が発生し、C#では予測不能な動作を引き起こします。イテレータは内部ポインタを保持しており、基になるコレクションが変更されると無効になります。これにより、コレクションの型と使用される削除パターンに応じて、要素のスキップ、クラッシュ、または無限ループが発生する可能性があります。
なぜ重要なのか
システムの安定性: 同時変更例外はアプリケーションを即座にクラッシュさせます。本番環境では、これはリクエストの破棄とサービス利用不可を意味します。この例外は、特定のデータを持つエッジケースで発生することが多く、テスト中に捕捉するのが困難です。
データ整合性: イテレーション中に削除ロジックが失敗すると、コレクションは部分的に変更された状態のままになります。一部のアイテムは削除されますが、削除されるべきだった他のアイテムは残ります。これにより、ダウンストリームロジックに影響を与える不整合なデータが生成されます。
デバッグの複雑さ: 同時変更バグはタイミングに依存し、特定のデータ組み合わせでのみ発生する可能性があります。一貫して再現することが困難であり、デバッグや信頼性の高い修正を難しくしています。
コード例
❌ 非準拠:
List<User> users = getUserList();
for (User user : users) {
if (!user.isActive()) {
users.remove(user); // ConcurrentModificationException
}
}
誤っている理由: ~からの削除 ユーザー 拡張forループでの反復処理が原因で ConcurrentModificationException。イテレータは、コレクションがイテレータの外部で変更されたことを検出し、即座に例外をスローします。最初の非アクティブユーザー以降のアクティブユーザーは処理されません。
✅ 準拠済み:
List<User> users = getUserList();
Iterator<User> iterator = users.iterator();
while (iterator.hasNext()) {
User user = iterator.next();
if (!user.isActive()) {
iterator.remove(); // Safe removal through iterator
}
}
これが重要である理由: 使用 iterator.remove() イテレーション中に項目を安全に削除します。イテレータは一貫した状態を維持し、残りの項目の処理を続行します。すべての非アクティブユーザーは例外なく正しく削除されます。
まとめ
イテレータを使用してください。 remove() イテレーション中の安全な削除のためのメソッド。あるいは、ストリームを併用して filter() 新しいコレクションを作成するか、 removeIf() 一括削除のため。コレクションの~を呼び出さないでください。 remove() イテレーション中に直接。

