Evitando ConcurrentModificationException ao Remover Elementos de uma Lista em Java
Ao trabalhar com coleções em Java, especialmente listas, é comum a necessidade de remover elementos durante a iteração. No entanto, essa prática pode levar a uma exceção conhecida como ConcurrentModificationException. Este artigo explica por que isso acontece e apresenta abordagens seguras para evitar esse problema.
O que é ConcurrentModificationException?
A ConcurrentModificationException
é lançada quando uma coleção é modificada estruturalmente (elementos são adicionados ou removidos) enquanto está sendo iterada por métodos como for-each
ou Iterator
, exceto através dos métodos do próprio Iterator
. Isso ocorre porque a estrutura interna da coleção muda durante a iteração, tornando o estado da iteração inconsistente.
Exemplo do Problema
Considere o seguinte código:
List<String> nomes = new ArrayList<>();
nomes.add("Alisson");
nomes.add("Bruna");
nomes.add("Cassio");
for (String nome : nomes) {
if (nome.equals("Bruna")) {
nomes.remove(nome); // Lança ConcurrentModificationException
}
}
Ao tentar remover "Bruna" durante o laço, a exceção será lançada.
Abordagens para Evitar o Problema
1. Usando uma Lista Auxiliar
Uma abordagem segura é criar uma lista auxiliar para armazenar os elementos que devem ser removidos e, após a iteração, removê-los da lista original:
List<String> nomesParaRemover = new ArrayList<>();
for (String nome : nomes) {
if (nome.equals("Bruna")) {
nomesParaRemover.add(nome);
}
}
nomes.removeAll(nomesParaRemover);
2. Iterando Sobre uma Cópia da Lista
Outra alternativa é criar uma cópia da lista e iterar sobre ela, removendo os elementos da lista original:
List<String> copia = new ArrayList<>(nomes);
for (String nome : copia) {
if (nome.equals("Cassio")) {
nomes.remove(nome);
}
}
3. Usando o Iterator
O uso explícito do Iterator
permite remover elementos de forma segura durante a iteração:
Iterator<String> iterator = nomes.iterator();
while (iterator.hasNext()) {
if (iterator.next().equals("Alisson")) {
iterator.remove();
}
}
Quando Usar Cada Abordagem?
- Lista Auxiliar: Ideal quando deseja remover todos os elementos que atendem a uma condição.
- Cópia da Lista: Útil quando a remoção é pontual ou quando a lógica exige iteração sobre o estado original.
- Iterator: Recomendado para remoção durante a iteração, especialmente quando a performance é importante e não se deseja criar listas auxiliares.
Conclusão
Remover elementos de uma lista durante a iteração exige cuidado para evitar a ConcurrentModificationException
. Escolher a abordagem correta depende do contexto da aplicação e da regra de negócio. Compreender essas técnicas é fundamental para escrever código Java robusto e seguro ao manipular coleções.