删除ArrayList对象问题

问题描述:

我有一个问题与删除从ArrayList中的赋值 工作时,如果我使用了“正常”的for循环的对象,它的工作原理如下删除ArrayList对象问题

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

希望你们能减轻我..

+0

如果你的问题是“为什么我得到一个错误”,它是因为您无法从正在迭代的列表中删除项目。如果相同的ISBN可以在列表中两次,您的第一个循环可能会有一个错误。 – 2012-04-01 03:28:19

你的替代方案,以避免ConcurrentModificationException的是:

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

收集所有要删除增强的for循环的记录,并在完成后遍历,您将删除所有找到的记录。

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

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

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

或者你可以使用第三方库像LambdaJ,这让所有的工作,你在幕后>

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

感谢队友,问题解决了:) – babygau 2012-04-01 04:05:12

+0

你救了我的命。谢谢 – 2017-11-20 11:23:00

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

+1

/golfclap使用'恶性' – 2012-04-01 03:28:44

当您在Java中使用增强型for-loop时,它使用列表的迭代器遍历列表。当您使用列表的remove函数移除项目时,这会干扰迭代器的状态,并且迭代器将抛出ConcurrentModificationException。 使用简单的for循环,您不会遇到这样的问题,因为您只使用列表,并且状态更改仅在列表本身发生。

+0

小心点亮一下如何使用迭代器删除Book对象 – babygau 2012-04-01 03:46:49

+0

它真的取决于你的应用程序和你想要的性能。 hashmap和arraylist迭代器的组合将做到这一点。 – amshali 2012-04-01 03:54:51

你在你的代码中的错误:

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)。当然,只有在有很多要删除的元素时才会担心。

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

但你可以做到以下几点:

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

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

+0

如果他添加超级粗“i--”,第一个循环会起作用。在if语句的底部。 – 2012-04-01 03:47:10

+0

你是什么意思? – 2012-04-01 03:48:25

+0

在最后一个中,它是从ArrayList中删除还是仅从迭代器中删除? – 2012-04-01 03:53:29

所有很好的答案。但我会让你重新思考它。我的意思是,你真的需要一个ArrayList还是一个HashMap会更好?如果你的对象列表有一个单一关键字(ISBN),并用它来获取每个对象,为什么不使用适合你的问题的集合呢?

你woud只做这

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