Eu tenho um ArrayList que eu quero iterar. Enquanto iterando sobre isso, tenho que remover elementos ao mesmo tempo. Obviamente, isso gera um java.util.ConcurrentModificationException
.
Qual é a melhor prática para lidar com esse problema? Devo clonar a lista primeiro?
Eu removo os elementos não no próprio loop, mas em outra parte do código.
Meu código fica assim:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething
pode ligar Test.removeA()
;
Respostas:
Duas opções:
originalList.removeAll(valuesToRemove)
no finalremove()
método no próprio iterador. Observe que isso significa que você não pode usar o loop for aprimorado.Como um exemplo da segunda opção, removendo quaisquer cadeias com um comprimento maior que 5 de uma lista:
fonte
Dos JavaDocs do ArrayList
fonte
Você está tentando remover o valor da lista no avançado "for loop", o que não é possível, mesmo se você aplicar algum truque (o que você fez no seu código). A melhor maneira é codificar o nível do iterador, conforme recomendado aqui.
Eu me pergunto como as pessoas não sugeriram a abordagem tradicional para loop.
Isso também funciona.
fonte
Você realmente deve apenas repetir a matriz da maneira tradicional
Sempre que você remover um elemento da lista, os elementos posteriores serão enviados adiante. Contanto que você não altere outros elementos além do iterativo, o código a seguir deve funcionar.
fonte
No Java 8, você pode usar a Interface de coleção e fazer isso chamando o método removeIf:
Mais informações podem ser encontradas aqui
fonte
Faça o loop da maneira normal, o
java.util.ConcurrentModificationException
é um erro relacionado aos elementos que são acessados.Então tente:
fonte
java.util.ConcurrentModificationException
não remover nada da lista. Complicado. :) Você não pode realmente chamar isso de "o caminho normal" para iterar uma lista.Ao iterar a lista, se você deseja remover o elemento, é possível. Vamos ver abaixo meus exemplos,
Eu tenho os nomes acima da lista Array. E eu quero remover o nome "def" da lista acima,
O código acima lança a exceção ConcurrentModificationException porque você está modificando a lista durante a iteração.
Portanto, para remover o nome "def" do Arraylist dessa maneira,
O código acima, através do iterador, podemos remover o nome "def" da Arraylist e tentar imprimir a matriz; você verá a saída abaixo.
Saída: [abc, ghi, xyz]
fonte
Uma opção é modificar o
removeA
método para isso -Mas isso significa que você
doSomething()
deve ser capaz de passariterator
oremove
método. Não é uma boa ideia.Você pode fazer isso na abordagem em duas etapas: No primeiro loop, quando você iterar sobre a lista, em vez de remover os elementos selecionados, marque- os como a serem excluídos . Para isso, você pode simplesmente copiar esses elementos (cópia superficial) em outro
List
.Depois que sua iteração estiver concluída, basta fazer a
removeAll
partir da primeira lista todos os elementos na segunda lista.fonte
Aqui está um exemplo em que eu uso uma lista diferente para adicionar os objetos a serem removidos e depois uso stream.foreach para remover elementos da lista original:
fonte
Em vez de usar Para cada loop, use normal para loop. por exemplo, o código abaixo remove todo o elemento na lista de matrizes sem fornecer java.util.ConcurrentModificationException. Você pode modificar a condição no loop de acordo com seu caso de uso.
fonte
Faça algo simples como este:
fonte
Uma solução Java 8 alternativa usando stream:
No Java 7, você pode usar o Guava:
Observe que o exemplo do Guava resulta em uma lista imutável que pode ou não ser o que você deseja.
fonte
Você também pode usar CopyOnWriteArrayList em vez de um ArrayList. Essa é a mais recente abordagem recomendada do JDK 1.5 em diante.
fonte
No meu caso, a resposta aceita não está funcionando, ela interrompe a exceção, mas causa alguma inconsistência na minha lista. A solução a seguir está funcionando perfeitamente para mim.
Neste código, adicionei os itens a serem removidos em outra lista e, em seguida, usei o
list.removeAll
método para remover todos os itens necessários.fonte
"Devo clonar a lista primeiro?"
Essa será a solução mais fácil, remova-a do clone e copie-o novamente após a remoção.
Um exemplo do meu jogo rummikub:
fonte
stones = (...) clone.clone();
seja supérfluo. Nãostones = clone;
faria o mesmo?stones
. Dessa forma, você nem precisa daclone
variável: #for (Stone stone : (ArrayList<Stone>) stones.clone()) {...
Se seu objetivo é remover todos os elementos da lista, você pode iterar sobre cada item e chamar:
fonte
Chego tarde, sei, mas respondo a isso porque acho que essa solução é simples e elegante:
Tudo isso é para atualizar de uma lista para outra e você pode fazer tudo de apenas uma lista. No método de atualização, você verifica a lista e pode apagar ou adicionar elementos entre a lista. Isso significa que ambos listam sempre o mesmo tamanho
fonte
Use o iterador em vez da lista de matrizes
Faça com que um conjunto seja convertido em iterador com correspondência de tipo
E vá para o próximo elemento e remova
Mover para o próximo é importante aqui, pois deve levar o índice para remover o elemento.
fonte
Que tal de
fonte
Basta adicionar uma pausa após a instrução ArrayList.remove (A)
fonte