Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Iterar sobre uma list e remover um objeto dela

Parte do meu código:

public List filtra(List contas) { 
Calendar dataAtual = Calendar.getInstance();
Iterator iterator = contas.iterator(); 
while (iterator.hasNext()) {
 Conta c2 = iterator.next(); 
 if (c2.getDataCriacao().get(Calendar.MONTH) == dataAtual .get(Calendar.MONTH) && c2.getDataCriacao().get(Calendar.YEAR) == dataAtual .get(Calendar.YEAR)) 
     contas.remove(c2);
}
return (filtro == null ? contas : filtro.filtra(contas)); }

A lógica é pegar as contas que foram criadas neste mês remove-las da minha lista. O problema é que eu recebo a exception java.util.ConcurrentModificationException na linha Conta c2 = iterator.next(); Sei que tem algo a ver com eu estar modificando uma lista durante a iteração. Mas não sei bem o motivo disto. O meu algoritmo tem por objetivo receber uma lista de contas, remover as contas que foram criadas este mes e passar esta lista para outro objeto. (outro filtro no caso).

Alguem pode ajudar?

3 respostas
solução!

Este é um problema bem recorrente, não só em java... O problema ocorre porque você altera a estrutura da collection sendo iterada (muda tamanho e indexações). Uma forma simples de resolver isso é na primeira "passada" marcar quem deve ser removido e depois efetivamente remove-los como explicitado a baixo:

public List filtra(List contas) { 
     List<Conta> contasARemover = new ArrayList<>();
     Calendar dataAtual = Calendar.getInstance();
     Iterator iterator = contas.iterator(); 
     while (iterator.hasNext()) {
         Conta c2 = iterator.next(); 
         if (c2.getDataCriacao().get(Calendar.MONTH) == dataAtual .get(Calendar.MONTH) && c2.getDataCriacao().get(Calendar.YEAR) == dataAtual .get(Calendar.YEAR)) 
            //Só guardamos a referencia (marcamos como candidato a remoção)
             contasARemover.add(c2);
     }
     //efetivamente removemos todos os marcados.
     contas.removeAll(contasARemover);
     return (filtro == null ? contas : filtro.filtra(contas)); 
}

Não testei o código a cima, mas teoricamente deve funcionar. Dúvidas nos dê uma resposta ;)

Funcionou amigo! Muito obrigado!

Eduardo, revistando este post após muito tempo sem acessar o alura, me toquei que o iterator é thread safe kkkkk

assim fica mais elegante:

public List filtra(List contas) { 
     Calendar dataAtual = Calendar.getInstance();
     Iterator iterator = contas.iterator(); 
     while (iterator.hasNext()) {
         Conta c2 = iterator.next(); 
         if (c2.getDataCriacao().get(Calendar.MONTH) == dataAtual .get(Calendar.MONTH) && c2.getDataCriacao().get(Calendar.YEAR) == dataAtual .get(Calendar.YEAR)) 
             iterator.remove();
     }
     return (filtro == null ? contas : filtro.filtra(contas)); 
}