Regola
Usa metodi sicuri durante la rimozione dallecollezioni.
Modificare una collezione mentre la si scorre spesso genera bug.
Linguaggi supportati: PY, Java, C/C++,
Swift/Objective-C, Ruby, PHP, Kotlin, Go,
Scala, Rust, Groovy, Dart, Julia, Elixir,
Erlang, Clojure, OCaml, LuaIntroduzione
Rimuovere elementi da una collezione durante l'iterazione provoca eccezioni di modifica concorrente in Java e un comportamento imprevedibile in C#. L'iteratore mantiene un puntatore interno che diventa non valido quando la collezione sottostante subisce modifiche. Ciò porta a elementi saltati, arresti anomali o loop infiniti a seconda del tipo di collezione e del criterio di rimozione utilizzato.
Perché è importante
Stabilità del sistema: Le eccezioni di modifica concorrente fanno crashare immediatamente l'applicazione. In produzione, questo si traduce in richieste perse e indisponibilità del servizio. L'eccezione si verifica spesso in casi limite con dati specifici, risultando difficile da individuare durante i test.
Integrità dei dati: Quando la logica di rimozione fallisce a metà iterazione, la collezione rimane in uno stato parzialmente modificato. Alcuni elementi vengono rimossi mentre altri che avrebbero dovuto esserlo rimangono al loro posto. Questo crea dati incoerenti che compromettono la logica successiva.
Complessità di debugging: I bug legati alla modifica concorrente dipendono dalle tempistiche e potrebbero manifestarsi solo con determinate combinazioni di dati. Sono difficili da riprodurre in modo coerente, il che rende arduo risolverli e correggerli efficacemente.
Esempi di codice
❌ Non conforme:
List<User> users = getUserList();
for (User user : users) {
if (!user.isActive()) {
users.remove(user); // ConcurrentModificationException
}
}
Perché è errato: La rimozione da utenti durante l'iterazione con un ciclo for avanzato provoca ConcurrentModificationException. L'iteratore rileva che la collezione è stata modificata al di fuori dell'iteratore stesso e genera immediatamente un'eccezione. Eventuali utenti attivi successivi al primo inattivo non vengono elaborati.
✅ Conforme:
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
}
}
Perché questo è importante: L'uso di iterator.remove() rimuove in sicurezza gli elementi durante l'iterazione. L'iteratore mantiene uno stato coerente e continua a elaborare gli elementi rimanenti. Tutti gli utenti inattivi vengono rimossi correttamente senza eccezioni.
Conclusione
Usa il metodo remove() dell'iteratore per una rimozione sicura durante l'iterazione. In alternativa, utilizza gli stream con filter() per creare nuove collezioni o removeIf() per la rimozione in blocco. Non chiamare mai la collezione remove() direttamente durante l'iterazione.

