2011-11-18 16 views
5

Tengo un problema al eliminar elementos de una lista mientras se recorre la lista. Código:Eliminación dinámica de elementos de la lista

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

recibo una ConcurrentModificationException, que estoy totalmente de entender. Estoy eliminando un elemento de una lista mientras estoy en el ciclo que pasa por la lista. Intuitivamente, eso arruinaría la indexación del ciclo.

Mi pregunta es, ¿de qué otra forma debería eliminar los elementos que no son enabled o selected de esta lista?

Respuesta

8

La forma más fácil de eliminar elementos de una lista en un bucle es el uso de un ListIterator y eliminar los elementos utilizando la rutina iterator.remove()

+0

No sé si es necesariamente el más fácil. 'remove()' es una pieza opcional de funcionalidad en la interfaz 'Iterator '. También vale la pena señalar que 'remove()' está en 'Iterator ', y simplemente es heredado por 'ListIterator '. – corsiKa

6

Modificación de una lista, mientras que la iteración a través de él, de una manera fuera de utilizar el iterador, resultados en un comportamiento indefinido Vas a tener que utilizar un iterador de forma explícita:

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

Ver this question por más.

+0

Hmm ya veo. Entonces, si quiero volver a convertir 'Iterator' en' Lista', ¿hay alguna manera más fácil que simplemente agregar cada elemento uno por uno en un bucle? – jamesfzhang

+2

Esto no convierte la 'Lista' en un' Iterador' - un 'Iterador' es solo un objeto que actúa sobre esa lista en sí mismo; es una interfaz para iterar a través de la lista. Cuando llamas a 'iter.remove()', realmente está modificando la lista subyacente. – Claudiu

+0

Guau, eso es increíble! Gracias. – jamesfzhang

0

El ConcurrentModificationException resulta del hecho de que la sintaxis para cada uno es solo azúcar sintáctica para usar la interfaz Iterator.

Los iteradores de lista tienen lo que se conoce como el atributo "fail-fast", lo que significa que cualquier cambio realizado en la lista aparte de la interfaz proporcionada por el iterador invalida inmediatamente dicho iterador. Intentar usar un iterador invalidado desencadena su excepción.

@Claudiu ya ha publicado este código, pero para mayor claridad, lo pondré aquí también. Para hacer lo que estás tratando de hacer, tendrás que soltar la sintaxis sofisticada y usar un iterador desnudo.

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

Otros han sugerido utilizar el iterador de la lista. Eso me ha resultado útil, pero lamentablemente se basa en un método, remove(), que se considera opcional mediante la interfaz Iterable<E>.

Dijo el Javadoc, nunca más (énfasis mío):

remove void()

elimina de la colección subyacente el último elemento devuelto por el iterador (operación opcional).

Para moverse, lo que me ha resultado más útil es una lista de eliminación.

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

Esto tiene el beneficio adicional de darle un historial de lo que eliminó, al igual que el método remove lo hace.

+0

Me gusta mucho esta (+1). Sin embargo, el elemento E debe tener una anulación adecuada del método de igualdad – GETah

+1

@GETah no necesariamente. Funcionará bien sin él, e incluso puede ser preferido. Puede hacer que provengan de un método de fábrica, en el que tenga una necesidad mucho menor del método de igualdad, confiando estrictamente en la referencia para la igualdad. – corsiKa

+1

¡Guau, me gusta mucho esto también! Muy bueno fuera del cuadro pensando. – jamesfzhang

Cuestiones relacionadas