2013-06-24 17 views
72

Durante il collegamento a un elenco, desidero rimuovere un elemento di un elenco in base a una condizione. Guarda il codice qui sotto.Rimozione di elementi da un elenco

Questo mi dà un'eccezione ConcurrentModification.

for (Object a : list) { 
    if (a.getXXX().equalsIgnoreCase("AAA")) { 
     logger.info("this is AAA........should be removed from the list "); 
     list.remove(a); 
    } 
} 

Come si può fare?

+2

Non è possibile rimuovere un elemento da una lista, mentre si sta iterazione di lista detto. Crea una copia e rimuovi gli oggetti da quello, o fallo direttamente all'iteratore. – thegrinner

risposta

55

È necessario utilizzare Iterator e chiamare remove() su iterator anziché utilizzare il ciclo for.

3
//first find out the removed ones 

List removedList = new ArrayList(); 
for(Object a: list){ 
    if(a.getXXX().equalsIgnoreCase("AAA")){ 
     logger.info("this is AAA........should be removed from the list "); 
     removedList.add(a); 

    } 
} 

list.removeAll(removedList); 
+3

Perché così complicato ... – m0skit0

+4

Non è complicato. È un altro modo per rimuovere una lista da un'altra. – Makky

+3

Stai creando un nuovo oggetto quando non è necessario, e probabilmente esegui il ciclo anche due volte l'elenco. – m0skit0

13

Non è possibile e non si deve modificare un elenco durante l'iterazione su di esso. Puoi risolvere questo temporaneamente salvando gli oggetti da rimuovere:

List<Object> toRemove = new ArrayList<Object>(); 
for(Object a: list){ 
    if(a.getXXX().equalsIgnoreCase("AAA")){ 
     toRemove.add(a); 
    } 
} 
list.removeAll(toRemove); 
+0

Perché non posso e non dovrei modificare un elenco mentre lo sto iterando? –

+2

@AlexVentura È a causa di come funziona il pattern iteratore.Se la lista dei riferimenti di iteratore cambia (specialmente la sua dimensione) senza che l'iteratore lo sappia, l'iteratore sarà "incasinato". –

22

Non puoi farlo perché lo stai già facendo.

Inorder per evitare questa situazione utilizzare Iterator, che si guarentees per rimuovere l'elemento dalla lista in modo sicuro ...

List<Object> objs; 
Iterator<Object> i = objs.iterator(); 
while (i.hasNext()) { 
    Object o = i.next(); 
    //some condition 
    i.remove(); 
} 
155
for (Iterator<String> iter = list.listIterator(); iter.hasNext();) { 
    String a = iter.next(); 
    if (...) { 
     iter.remove(); 
    } 
} 

Fare un'ipotesi aggiuntiva che la lista è di stringhe. Come già risposto, è necessario un list.iterator(). Lo listIterator può fare anche un po 'di navigazione.

5

Oltre a tutte le eccellenti soluzioni offerte qui vorrei offrire una soluzione diversa.

Non sono sicuro di poter aggiungere dipendenze, ma se è possibile, è possibile aggiungere lo https://code.google.com/p/guava-libraries/ come dipendenza. Questa libreria aggiunge il supporto per molte operazioni funzionali di base a Java e può rendere il lavoro con le raccolte molto più semplice e più leggibile.

Nel codice ho sostituito il tipo di Elenco con T, dal momento che non conosco il tipo di elenco digitato.

Questo problema può essere risolto con la guava come questo:

List<T> filteredList = new Arraylist<>(filter(list, not(XXX_EQUAL_TO_AAA))); 

E da qualche altra parte poi si definiscono XXX_EQUAL_TO_AAA come:

public static final Predicate<T> XXX_EQUAL_TO_AAA = new Predicate<T>() { 
    @Override 
    public boolean apply(T input) { 
     return input.getXXX().equalsIgnoreCase("AAA"); 
    } 
} 

Tuttavia, questo è probabilmente eccessivo nella vostra situazione. È solo qualcosa che diventa sempre più potente più lavori con le collezioni.

OHW, anche, avete bisogno di queste importazioni statiche:

import static com.google.common.base.Predicates.not; 
import static com.google.common.collect.Collections2.filter; 
Problemi correlati