2011-11-18 1 views
5

Sto riscontrando un problema durante la rimozione di elementi di un elenco durante l'iterazione nell'elenco. Codice:Rimuove dinamicamente elementi dall'elenco

For (WebElement element: list){ 
    if (!element.isEnabled() || !element.isSelected()){ 
     list.remove(element); 
    } 
} 

ho un ConcurrentModificationException, che capisco perfettamente. Sto rimuovendo un elemento da una lista mentre sono nel ciclo che passa attraverso la lista. Intuitivamente, ciò avrebbe rovinato l'indicizzazione del ciclo.

La mia domanda è, in quale altro modo dovrei rimuovere elementi che non sono enabled o selected da questo elenco?

risposta

8

Il modo più semplice per rimuovere elementi da una lista in un ciclo è quello di utilizzare un ListIterator e rimuovere gli elementi utilizzando la routine iterator.remove()

+0

Non so se è necessariamente il più facile. 'remove()' è una funzionalità opzionale sull'interfaccia 'Iterator '. Vale anche la pena notare che 'remove()' è su 'Iterator ', ed è semplicemente ereditato da 'ListIterator '. – corsiKa

6

Modifica di una lista, mentre l'iterazione attraverso di essa, in un certo senso al di fuori di utilizzare l'iteratore, i risultati nel comportamento indefinito. Dovrete usare un iteratore in modo esplicito:

Iterator<WebElement> iter = list.iterator(); 
while (iter.hasNext()) { 
    WebElement element = iter.next(); 
    if (!element.isEnabled() || !element.isSelected()) { 
     iter.remove(); 
    } 
} 

Vedi this question di più.

+0

Hmm vedo. Quindi, se voglio riconvertire 'Iterator' in un' Elenco', c'è un modo più semplice di aggiungere semplicemente ogni elemento uno alla volta in un ciclo? – jamesfzhang

+2

Ciò non converte la 'Lista' in un' Iterator' - un 'Iterator' è solo un oggetto che agisce su quella lista stessa - è un'interfaccia per iterare attraverso la lista. Quando chiami 'iter.remove()', sta davvero modificando la lista sottostante. – Claudiu

+0

Wow, è incredibile! Grazie. – jamesfzhang

0

Il ConcurrentModificationException deriva dal fatto che la sintassi for-each è solo zucchero sintattico per l'utilizzo dell'interfaccia Iterator.

Gli iteratori di lista hanno l'attributo "fail-fast", ovvero qualsiasi modifica apportata all'elenco a prescindere dall'interfaccia fornita dall'iteratore, annulla immediatamente detto iteratore. Cercando di utilizzare un iteratore invalidato si attiva l'eccezione.

@Claudiu ha già pubblicato questo codice, ma per chiarezza, lo inserirò anche qui. Per fare ciò che stai cercando di fare, dovrai eliminare la sintassi di fantasia e usare un Iterator spoglio.

Iterator<WebElement iter = list.iterator(); 
while (iter.hasNext()) { 
    WebElement element = iter.next(); 
    if (!element.isEnabled() || !element.isSelected()) { 
     iter.remove(); 
    } 
} 
3

Altri hanno suggerito di utilizzare l'iteratore di elenco. Ciò mi è stato utile, ma sfortunatamente si basa su un metodo, remove(), che è considerato opzionale dall'interfaccia Iterable<E>.

Disse il Javadoc, Nevermore (enfasi mia):

remove vuoto()

rimuove dalla collezione sottostante l'ultimo elemento restituito dal all'iteratore (operazione facoltativa).

Per aggirare ciò che è risultato più utile per me è una lista di rimozione.

List<E> removed = new ArrayList<E>(); 
for(E element : list) { 
    if(someCondition) removed.add(element); 
} 
list.removeAll(removed); 

Questo ha il vantaggio di dare una storia di quello che è stato rimosso, proprio come il metodo remove fa.

+0

Mi piace molto questo (+1). Tuttavia, l'elemento E dovrebbe avere un override appropriato del metodo uguale – GETah

+1

@ GETah non necessariamente. Funzionerà bene senza di esso, e potrebbe anche essere preferito. Potresti averli provenire da un metodo di fabbrica, in cui hai molto meno bisogno del metodo degli uguali, basandoti strettamente sul riferimento per l'uguaglianza. – corsiKa

+1

Wow, mi piace anche questo! Molto buono fuori dagli schemi. – jamesfzhang