style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

java.util.ConcurrentModificationException como se hace ¿?

Resulta que me veo nuevamento con la tarea de tener que quitar determinados elementos de una lista de acuerdo a ciertas condiciones si se cumple se va y sino se queda..

mi codigo es mas o menos así:

...
for(Empleado emp : listaEmpleados){
                if (emp.plaza == null){
                    listaEmpleados.remove(emp);
                }
            }
...

parece logico no? si un empleado no tiene plaza no me sirve en mi lista.. bien eso da un error en tiempo de ejecución

[See nested exception: java.util.ConcurrentModificationException]

lo que me indica que no puedo modificar la lista mientras se este iterando (la misma lista).

¿como lo resolvi? creando un clon de la lista, y removiendo los elementos de esta lista mientras itero la original, luego regreso el contenido del clon a la original y listo.

Mi pregunta es si existe otra manera de hacerlo sin tener que crear una lista clon o alguna magia de groovy?

Saludos.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de Shadonwk

benditas sean las closures

listaEmpleados =listaEmpleados.findAll {it.plaza!=null}

No en groovy pero lo que yo

No en groovy pero lo que yo hago es crear una lista y meter ahí los que voy a eliminar:

List<Empleado> toRemove = new ArrayList<Empleado>();
for ( Empleado e : listaEmpleados ) {
    if ( condicion ) {
        toRemove.add( e );
    }
}
listaEmplados.removeAll( toRemove );
Imagen de ezamudio

El otro for

El foreach de Java está hecho para iterar una lista sin modificarla. Es pura azúcar sintáctica; cuando lo compilas se convierte en algo así:

for (Iterator<Empleado> tmpvarblabla=listaEmpleados.iterator();tmpvarblabla.hasNext();) {
  final Empleado emp = tmpvarblabla.next();
  //Y luego aquí va tu código
}

Cuando quitas el elemento de la lista directamente, el iterator se queja de que la lista sobre la que itera ya fue modificada.

Si tú haces tooooodo ese código del for, en vez del foreach, entonces tienes acceso al iterador, cosa que es muy útil porque tiene un método para quitar el elemento actual de la colección, sin que tengas ese problema:

for (Iterator<Empleado> iter=listaEmpleados.iterator();iter.hasNext();) {
  final Empleado emp = iter.next();
  if (algunaCondicion) { iter.remove(); }
}
Imagen de Shadonwk

@Oscar casi biene siendo lo

@Oscar casi biene siendo lo mismo que clonar la lista pero un poco mas eficiente al no desperdiciar memoria en todos los elementos...

@Enrique pense en poner el for completo, pero pense que pasaria lo mismo, ahora me doy cuenta que no... es muy util tenerlo en cuenta.

Imagen de 5uRFi

Duda

Saludos Oscar.

Se que es un tema ya de tiempo pero me surge la inquietud en base a que se eliminan los valores.

En un principio pensé que era en base a cada atributo de la clase Empleado. Por lo que realice un pequeño ejemplo pasandole los valores a la segunda lista por separado, pero que los valores fueran los mismos a la lista 1, y no me elimino ninguno.

Por lo que llego a la conclucion de que la eliminacion se hace por referencia? o me equivoco?.

No precisamente, se quitan

No precisamente, se quitan los que den true en el metodo equals:

http://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html#remove(java.lang.Object)

Si no sobreescribes el metodo equals por default va a revisar las referencias como en la prueba que hiciste.

Si lo especificas entonces la coleccion sabra cuando un objeto es igual a otro:

oreyes:remove $ cat Employee.java
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;

class Employee {
    private final String name;
    private final int id;
    public Employee( String name, int id ) {
        this.name = name;
        this.id = id;
    }
    public boolean equals( Object other ) {
        return other instanceof Employee && this.id == ((Employee)other).id;
    }
    public String toString() {
        return String.format("%s(id:%d)", name,id );
    }
}
class Main {
    public static void main( String ... args ) {
        List<Employee> employees = list(
            employee("Hugo", 1),
            employee("Paco", 2),
            employee("Luils", 3)
         );

        employees.removeAll( list(
            employee("Donald", 1),
            employee("Rico McPato", 2),
            employee("Pascual", 10)
         ));
        System.out.println( employees );

    }
    public static List<Employee> list( Employee ... list ) {
        return new ArrayList<Employee>(Arrays.asList(list));
    }
    public static Employee employee( String name, int id ) {
        return new Employee(name, id );
    }
}
oreyes:remove $ javac Employee.java
oreyes:remove $ java Main
[Luils(id:3)]

Por cierto, la forma correcta de hacer esto es como señala ezamudio, con el otro for.

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">