Erro com Collections: java.util.ConcurrentModificationException

Olá Pessoal!

Estou com um problema em trabalhar com collections em um trecho do meu aplicativo. Segue o código

for(Despesa d : despesas) {
            if(!d.isVitalicia()) {
                if (!pagamentoDespesa.isPaga(d)) {
                    List<ParcelaDespesa> parcelas = d.getParcelasDespesa();

                    if(parcelas != null) {
                        Iterator<ParcelaDespesa> it = parcelas.iterator();
                        
                        while (it.hasNext()) {                                                        
                            //ConcurrentModificationException é lancado na segunda iteração.
                            ParcelaDespesa p = it.next();

                            if (!pagamentoDespesa.isPaga(p))
                                 //se eu tirar esse código funciona, 
                                 //porém não e o comportamento que eu desejo.
                                 d.addParcelaDespesa(p);
                        }
                    }
                    retornar.add(d);
                }
            }
            else {
                //tratar despesas vitalícias
            }            
        } 

Segue abaixo o código que tem em Despesa.addParcelaDespesa(ParcelaDespesa);

public void addParcelaDespesa(ParcelaDespesa parcelaDespesa) {
        if (parcelaDespesa.getIdParcelaDespesa() == 0) {
            if(parcelasDespesa.size()==0)            
                    parcelaDespesa.setIdParcelaDespesa(1);
            else
                parcelaDespesa.setIdParcelaDespesa(parcelasDespesa.get(parcelasDespesa.size()-1).getIdParcelaDespesa()+1);  
        }
        
        if(parcelaDespesa.getDespesa() == null)    
            parcelaDespesa.setDespesa(this);
        
        parcelasDespesa.add(parcelaDespesa);
    }

Já tentei implementar em ParcelaDespesa a interface Cloneable e sobreescrever o clone. Não funcionou também :cry:

Segue stacktrace lancado;

Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:449)
        at java.util.AbstractList$Itr.next(AbstractList.java:420)
        at gfi.modelo.Despesa.obterDespesasPagar(Despesa.java:185)
        at gfi.forms.PagarDespesasMestre.btnPesquisar2ActionPerformed(PagarDespesasMestre.java:165)
        at gfi.forms.PagarDespesasMestre.access$000(PagarDespesasMestre.java:19)
        at gfi.forms.PagarDespesasMestre$1.actionPerformed(PagarDespesasMestre.java:56)
        at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1849)
        at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2169)
        at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:420)
        at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:258)
        at javax.swing.plaf.basic.BasicButtonListener$Actions.actionPerformed(BasicButtonListener.java:285)
        at javax.swing.SwingUtilities.notifyAction(SwingUtilities.java:1571)
        at javax.swing.JComponent.processKeyBinding(JComponent.java:2763)
        at javax.swing.JComponent.processKeyBindings(JComponent.java:2798)
        at javax.swing.JComponent.processKeyEvent(JComponent.java:2726)
        at java.awt.Component.processEvent(Component.java:5265)
        at java.awt.Container.processEvent(Container.java:1966)
        at java.awt.Component.dispatchEventImpl(Component.java:3955)
        at java.awt.Container.dispatchEventImpl(Container.java:2024)
        at java.awt.Component.dispatchEvent(Component.java:3803)
        at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1810)
        at java.awt.DefaultKeyboardFocusManager.dispatchKeyEvent(DefaultKeyboardFocusManager.java:672)
        at java.awt.DefaultKeyboardFocusManager.preDispatchKeyEvent(DefaultKeyboardFocusManager.java:920)
        at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:798)
        at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:636)
        at java.awt.Component.dispatchEventImpl(Component.java:3841)
        at java.awt.Container.dispatchEventImpl(Container.java:2024)
        at java.awt.Window.dispatchEventImpl(Window.java:1774)
        at java.awt.Component.dispatchEvent(Component.java:3803)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:463)
        at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:242)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:163)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:157)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:149)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:110)

Qualquer ajuda será bem-vinda!

Abraços

Ramon

Esse erro é gerado qdo vc tenta modificar o conteudo de uma coleção no loop do iterator.

Obrigado pela resposta!

Isso eu já sei. O que eu quero saber é onde está sendo alterado o item da collection? E qual outra estratégia de implementação que eu posso usar para sanar esse problema.

Alguma sugestão?

Abs

Ramon

vc pode usar a estratégia ‘separate collections’, onde você trabalha com duas coleções onde uma vc vai adicionando elementos da outra que vc deve tratar.

[quote=Fabrício Cozer Martins]vc pode usar a estratégia ‘separate collections’, onde você trabalha com duas coleções onde uma vc vai adicionando elementos da outra que vc deve tratar.

[/quote]

Obrigado! Eu usei a estratégia que voce me indicou e funcionou. Mas não gostei de ter que usar duas collections para uma operação tão simples. Será que isso não é um problema de thread? Já usei o Collections.synchronizedList(minhalista) e deu o mesmo erro.
Não sei oque pode ser.

Abraços!

Ramon

a moral da historia eh: nao modifique a collection durante a iteracao, pq pode dar problemas - mesmo com synchronized, como vc esta modificando a lista durante a iteracao no mesmo thread, a excecao eh lancada…
a sugestao dada eh a mais simples mesmo

ConcurrentModificationException não diz respeito nenhum a modificação entre threads.

Essa exception é lançada sempre que você fizer alguma modificação estrutural em uma collection sem ser pelo iterator. A solução é você realizar as alterações pelo iterator ou usar colections separadas.

1 curtida

pois eh, mas muitas pessoas jah erraram (eu, inclusive) achando que a collection estava sendo modificada por outra thread ou coisa parecida…
pelo menos para mim a excecao eh um pouco sugestiva nesse sentido, alem do javadoc mencionar:

Eita… eu estou com o mesmo problema que ele (ou ao menos parecido) e não sei como resolver. Se puderem me explicar passo-a-passo por favor, eu ficaria muito agradecido!

Segue abaixo parte do meu código:

i=0;
while (busca.hasNext()){
	p2 [i] = new Produto();
	p2 [i] = (Produto) busca.next();
	String nomeproduto = nome.getText();
	if (nomeproduto.equals(p2[i].getNome())) {
		quantidade.setText(Integer.toString(p[i].getQuantidade()));
		preco.setText(Integer.toString(p[i].getPreco()));
		break;
	}else{
		i++;
	}
}

Sendo que lá em cima, no início do código, eu criei:

ArrayList <Produto> loja = new ArrayList<Produto>();  
Iterator busca = loja.iterator();
Produto [] p = new Produto[8];
Produto [] p2 = new Produto[8];
int i = 0;

O erro é o mesmo ( java.util.ConcurrentModificationException ) e está marcado nessa linha : p2 [i] = (Produto) busca.next();

Dêem-me uma mãozinha, pessoal. Tou precisando disso pra ontem!! =/

Outro Collection? É muito Collection! Eu faço assim:

for(int i = 0; i < messages.size(); i++){ if(messages.get(i).getStatus().equals(InstantaneousMessage.STATUS.COMMITED)){ messages.remove(messages.get(i)); --i; } }

Mais uma opção…

		for (Iterator&lt;Pessoa&gt; iterator = getListaPessoa().iterator(); iterator
				.hasNext();) {

			if (iterator.next().isSelecionado()) {

				iterator.remove();
			}
		}

Será que o pessoal de 2006 já não tinha percebido essas duas soluções?

Estava passando pelo mesmo problema,pirando achando que era problemas de thread, to usando sockets e thread, mas o –i; resolveu meu problema!

valeu pessoal!

–i me salvou tb… tks!

Tive o mesmo problema quando eu tentava assim:

Collection<String> nodes = this.getNodes();
     for (String node : nodes)
          this.removeNode(node);

Resolvi da seguinte forma:

Collection<String> nodes = this.getNodes();
while (!nodes.isEmpty()) {
     Iterator<String> nodesIterator = nodes.iterator();
     if (nodesIterator.hasNext())
          this.removeNode(nodesIterator.next());
     nodes = this.getNodes();
}

Usando Iterator é a melhor forma:


Iterator<SeuObjeto> it = suaLista.iterator();

while(it.hasNext()){
            SeuObjeto item = it.next();
            if(item.getCondicao() == true){                                
            suaLista.remove(item);
            }
        }

Essa é a receita, igual o amigo acima falou.

[quote=oddy.silva]Usando Iterator é a melhor forma:


Iterator<SeuObjeto> it = suaLista.iterator();

while(it.hasNext()){
            SeuObjeto item = it.next();
            if(item.getCondicao() == true){                                
            suaLista.remove(item);
            }
        }

Essa é a receita, igual o amigo acima falou.[/quote]

Há um problema nesse código que ainda pode disparar a ConcurrentModificationException

Segunda a Sun a interface java.util.Iterator define:

An iterator over a collection. Iterator takes the place of Enumeration in the Java collections framework. Iterators differ from enumerations in two ways:

* Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
* Method names have been improved. 

Ou seja ele foi especialmente criado para permitir a remoção de elementos de uma coleção durante uma iteração além das outras duas funcionalidades de verificacao e busca do proximo elemento que já eram providas pela interface Enumeration, porém no Iterator com nomes mais simples.

No seu código voce não remove o elemento da lista através do método remove() do Iterator.

Os três métodos do Iterator:

boolean hasNext() : Returns true if the iteration has more elements.
Object next() : Returns the next element in the iteration.
void remove() : Removes from the underlying collection the last element returned by the iterator (optional operation).

Descrição do método remove:

public void remove()

Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next. The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.

Throws:
    UnsupportedOperationException - if the remove operation is not supported by this Iterator. 
    IllegalStateException - if the next method has not yet been called, or the remove method has already been called after the last call to the next method.

O código correto ficaria assim:


Iterator<SeuObjeto> it = suaLista.iterator();

while(it.hasNext()){
            SeuObjeto item = it.next();
            if(item.getCondicao() == true){                                
            it.remove();
            }
        }

Ola, eu tive o mesmo problema e resolvi da seguinte maneira, eu encapsulei a minha Collection a ser acessada pelas demais Threads e
sincronizei os metodos get e set de acesso, logo todos que precisam acessar a Collection, acessam pelo get ou set entao isso nao da
java.util.ConcurrentModificationException, no meu caso funcionou muito bem.

Espero q eu tenha ajudado

[quote=FrancoC][quote=oddy.silva]Usando Iterator é a melhor forma:


Iterator<SeuObjeto> it = suaLista.iterator();

while(it.hasNext()){
            SeuObjeto item = it.next();
            if(item.getCondicao() == true){                                
            suaLista.remove(item);
            }
        }

Essa é a receita, igual o amigo acima falou.[/quote]

Há um problema nesse código que ainda pode disparar a ConcurrentModificationException

Segunda a Sun a interface java.util.Iterator define:

An iterator over a collection. Iterator takes the place of Enumeration in the Java collections framework. Iterators differ from enumerations in two ways:

* Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
* Method names have been improved. 

Ou seja ele foi especialmente criado para permitir a remoção de elementos de uma coleção durante uma iteração além das outras duas funcionalidades de verificacao e busca do proximo elemento que já eram providas pela interface Enumeration, porém no Iterator com nomes mais simples.

No seu código voce não remove o elemento da lista através do método remove() do Iterator.

Os três métodos do Iterator:

boolean hasNext() : Returns true if the iteration has more elements.
Object next() : Returns the next element in the iteration.
void remove() : Removes from the underlying collection the last element returned by the iterator (optional operation).

Descrição do método remove:

public void remove()

Removes from the underlying collection the last element returned by the iterator (optional operation). This method can be called only once per call to next. The behavior of an iterator is unspecified if the underlying collection is modified while the iteration is in progress in any way other than by calling this method.

Throws:
    UnsupportedOperationException - if the remove operation is not supported by this Iterator. 
    IllegalStateException - if the next method has not yet been called, or the remove method has already been called after the last call to the next method.

O código correto ficaria assim:


Iterator<SeuObjeto> it = suaLista.iterator();

while(it.hasNext()){
            SeuObjeto item = it.next();
            if(item.getCondicao() == true){                                
            it.remove();
            }
        }

[/quote]

Perfeito, sua solução resolveu o meu problema. Valeu!!! :thumbup:

Opa…

Seu --i também solucionou meu problema!

Valeuu… :smiley: