2012-04-01 16 views
5

tengo un problema con la eliminación de un objeto a partir de ArrayList cuando se trabaja en la asignación Si utilizo el "normal" para el lazo, funciona de la siguiente maneraArrayList Extracción tema objeto

public void returnBook(String isbn){   
    for (int i = 0; i < booksBorrowed.size(); i++){    
     if (booksBorrowed.get(i).getISBN() == isbn){ 
      booksBorrowed.get(i).returnBook(); 
      booksBorrowed.remove(i);     
     } 
    } 
} 

Sin embargo, cuando estoy tratando de simplificar el código con una mejora de bucle, que no funciona y que muestra java.util.ConcurrentModificationException error:

public void returnBook(String isbn){   
     for (Book book: booksBorrowed){    
      if (book.getISBN() == isbn){ 
       book.returnBook(); 
       booksBorrowed.remove(book);     
      } 
     } 
} 

Espero que ustedes me podría aligerar ..

+0

Si su pregunta es "¿Por qué recibo un error" es porque no puede eliminar elementos de una lista sobre la que está iterando. Y su primer ciclo puede tener un error, si el mismo ISBN puede estar en la lista dos veces. –

Respuesta

7

sus alternativas para evitar una ConcurrentModificationException son:

List<Book> books = new ArrayList<Book>(); 
books.add(new Book(new ISBN("0-201-63361-2"))); 
books.add(new Book(new ISBN("0-201-63361-3"))); 
books.add(new Book(new ISBN("0-201-63361-4"))); 

recoger todos los registros que desea eliminar el bucle for mejorado, y después de que termine la iteración , eliminas todos los registros encontrados.

ISBN isbn = new ISBN("0-201-63361-2"); 
List<Book> found = new ArrayList<Book>(); 
for(Book book : books){ 
    if(book.getIsbn().equals(isbn)){ 
     found.add(book); 
    } 
} 
books.removeAll(found); 

O puede utilizar una ListIterator que cuenta con el apoyo de un método de eliminación durante la misma iteración.

ListIterator<Book> iter = books.listIterator(); 
while(iter.hasNext()){ 
    if(iter.next().getIsbn().equals(isbn)){ 
     iter.remove(); 
    } 
} 

O puede utilizar una biblioteca de terceros, como LambdaJ y hace todo el trabajo para usted detrás de las escenas>

List<Book> filtered = select(books, 
       having(on(Book.class).getIsbn(), 
         is(new ISBN("0-201-63361-2")))); 
+0

Gracias amigo, Problema resuelto :) – babygau

+0

Me salvaste la vida. Gracias –

4

No debería estar haciendo ninguna de las dos cosas, ya que al final causará problemas. En su lugar, use el iterador de ArrayList para ayudarlo a recorrer la lista y luego eliminar solo con el iterador. Esto ayudará a prevenir errores de modificación concurrentes perniciosos.

+1

/golfclap uso de 'pernicioso' –

0

Cuando está utilizando el for-loop mejorado en Java, utiliza el iterador de la lista para iterar sobre la lista. Cuando se quita un elemento con la función de eliminación de la lista, que pueda interferir con el estado del iterador iterador y lanzará una ConcurrentModificationException. Con el simple bucle for que no tienen ese problema, ya que sólo está utilizando la lista y el cambio de estado ocurre solamente en la propia lista.

+0

Para aclararme un poco sobre cómo usar el iterador para eliminar el objeto Libro – babygau

+0

, realmente depende de cuál es su aplicación y qué tipo de rendimiento desea. Una combinación de hashmap e iterador de arrays hará eso. – amshali

1

ha encontrado un error en el código:

for (int i = 0; i < booksBorrowed.size(); i++){    
    if (booksBorrowed.get(i).getISBN() == isbn){ 
     booksBorrowed.get(i).returnBook(); 
     booksBorrowed.remove(i);     
    } 
} 

Se salta siguientes elementos después que había retirado. P.ej. cuando eliminaste el elemento "0º", el 1º se convierte en el 0º, pero este código no itera a través de él.

Ésta es una versión correcta:

for (int i = booksBorrowed.size() - 1; i >= 0; i--){    
    if (booksBorrowed.get(i).getISBN() == isbn){ 
     booksBorrowed.get(i).returnBook(); 
     booksBorrowed.remove(i);     
    } 
} 

Pero este no es el mejor enfoque, debido a su complejidad es O (n^2).

Una mejor opción es agregar todos los elementos retenidos a otra colección y luego copiarlos de nuevo a la lista original con el tamaño truncado. Su complejidad es O (n). Por supuesto, es una preocupación solo si hay muchos elementos para eliminar.

P.S. eliminar en un iterador de rupturas de construcción para cada uno, por lo que no es una forma válida de procesar la lista en este caso.

Pero se puede hacer lo siguiente:

for (Iterator<String> i = a.iterator(); i.hasNext();) { 
     Book next = i.next(); 
     if (book.getISBN() == isbn){ 
      book.returnBook(); 
      i.remove(i);     
     } 
    } 

Una vez más, la complejidad es O (n^2) en este caso.

+0

El primer ciclo funciona si agrega el "i--; en la parte inferior de la declaración if. –

+0

¿qué quieres decir? –

+0

En el último, ¿se elimina de ArrayList o solo del iterador? –

2

Todas las buenas respuestas. Pero te sugeriría para que lo reconsiderases. Es decir, lo que realmente necesita una ArrayList o una HashMap sería mejor? Si su lista de objetos tiene una clave única (ISBN) y la usa para obtener cada objeto, ¿por qué no utilizar una colección apropiada para su problema?

Usted woud hace sólo esto

public void returnBook(String isbn){   
    Book book = (Book) booksBorrowed.remove(isbn);    
    book.returnBook();  
}