删除ArrayList对象问题

在处理赋值时,我遇到了从ArrayList中删除对象的问题如果我使用“normal”for循环,它的工作原理如下

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); } } } 

但是,当我尝试使用增强的for循环来简化代码时,这不起作用并显示java.util.ConcurrentModificationException错误:

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

希望你们能照亮我…

避免ConcurrentModificationException的替代方法是:

 List books = new ArrayList(); 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"))); 

在增强型for循环中收集要删除的所有记录,并在完成迭代后删除所有找到的记录。

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

或者您可以使用ListIterator ,它在迭代过程中支持remove方法。

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

或者您可以使用像LambdaJ这样的第三方库,它可以在幕后为您完成所有工作>

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

你真的不应该这样做,因为它们最终会导致问题。 而是使用ArrayList的迭代器来帮助您遍历列表,然后仅使用迭代器删除。 这有助于防止恶意的并发修改错误。

所有好的答案。 但我会劝你重新思考它。 我的意思是,你真的需要一个ArrayList或者HashMap会更好吗? 如果您的对象列表具有单一密钥(ISBN),并且您使用它来获取每个对象,为什么不使用适合您的问题的集合?

你只会这样做

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

你的代码中有一个错误:

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

它会在删除之后跳过下一个元素。 例如,当您删除'0th'元素时,1st变为0,但此代码不会迭代它。

这是一个正确的版本:

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

但这不是最好的方法,因为它的复杂性是O(n ^ 2)。

更好的方法是将所有保留的项目添加到另一个集合,然后将它们复制回原始列表,并缩小大小。 它的复杂性是O(n)。 当然,只有要删除许多元素才会引起关注。

在for-each构造中删除PS会破坏迭代器,因此在这种情况下处理列表不是一种有效的方法。

但是你可以做到以下几点:

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

同样,在这种情况下复杂度为O(n ^ 2)。

当您在Java中使用增强的for循环时,它使用列表的Iterator迭代列表。 当您使用列表的remove函数删除项时,这将干扰迭代器的状态,迭代器将抛出ConcurrentModificationException。 使用简单的for循环,您没有这样的问题,因为您只使用列表,并且状态更改仅在列表本身中发生。