2012-04-01 79 views
5

Tôi có một vấn đề với xóa một đối tượng từ ArrayList khi làm việc trên sự phân công Nếu tôi sử dụng "bình thường" cho vòng lặp, nó hoạt động như sauLoại bỏ ArrayList vấn đề đối tượng

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

Tuy nhiên, khi tôi cố gắng để đơn giản hóa mã với tăng cường cho vòng lặp, điều đó không làm việc và hiển thị java.util.ConcurrentModificationException lỗi:

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

Hy vọng các bạn có thể làm sáng tôi dậy ..

+0

Nếu câu hỏi của bạn là "Tại sao tôi lại nhận được một lỗi" đó là vì bạn không thể xóa các mục khỏi danh sách bạn đang lặp lại. Và vòng lặp đầu tiên của bạn có thể có lỗi trong đó, nếu cùng một ISBN có thể nằm trong danh sách hai lần. –

Trả lời

7

lựa chọn thay thế của bạn để tránh một ConcurrentModificationException là:

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

Thu thập tất cả các hồ sơ mà bạn muốn xóa trên tăng cường cho vòng lặp, và sau khi bạn hoàn thành lặp , bạn xóa tất cả các bản ghi đã tìm thấy.

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

Hoặc bạn có thể sử dụng ListIterator có hỗ trợ phương pháp xóa trong khi lặp lại chính nó.

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

Hoặc bạn có thể sử dụng một thư viện của bên thứ ba như LambdaJ và nó làm cho tất cả các công việc cho bạn đằng sau hậu trường>

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

Cảm ơn bạn đời, Đã giải quyết vấn đề :) – babygau

+0

Bạn đã cứu mạng tôi. Cảm ơn –

4

Bạn thực sự không nên làm vì họ sẽ gây ra vấn đề cuối cùng. Thay vào đó hãy sử dụng trình lặp của ArrayList để giúp bạn lặp qua danh sách và sau đó chỉ xóa bỏ với trình lặp. Điều này sẽ giúp ngăn ngừa các lỗi sửa đổi đồng thời nguy hiểm.

+1

/golfclap sử dụng 'pernicious' –

0

Khi bạn đang sử dụng vòng lặp nâng cao trong Java, nó sử dụng Iterator của danh sách để lặp qua danh sách. Khi bạn loại bỏ một mục có chức năng xóa của danh sách, điều đó sẽ ảnh hưởng đến trạng thái của trình lặp và trình vòng lặp sẽ ném ra một ConcurrentModificationException. Với vòng lặp đơn giản, bạn không có vấn đề như vậy bởi vì bạn chỉ sử dụng danh sách và thay đổi trạng thái chỉ xảy ra trong danh sách.

+0

Chăm sóc để khai sáng cho tôi một chút về cách sử dụng trình lặp để loại bỏ đối tượng Book – babygau

+0

nó thực sự phụ thuộc vào ứng dụng của bạn là gì và hiệu suất kinda bạn muốn. Một sự kết hợp giữa trình băm chéo và trình sắp xếp mảng sẽ làm điều đó. – amshali

1

Bạn có một lỗi trong mã của bạn:

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

Nó bỏ qua các yếu tố tiếp theo sau những người đã bị gỡ. Ví dụ. khi bạn đã xóa phần tử '0th', thứ 1 trở thành 0, nhưng mã này không lặp qua nó.

Đây là phiên bản chính xác:

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

Nhưng đây không phải là phương pháp tốt nhất, vì nó phức tạp là O (n^2).

Tốt nhất là thêm tất cả các mục đã lưu vào bộ sưu tập khác và sau đó sao chép chúng trở lại danh sách gốc với kích thước cắt bớt. Độ phức tạp của nó là O (n). Tất nhiên, đó là một mối quan tâm chỉ khi có nhiều yếu tố để loại bỏ.

P.S. loại bỏ trong một công cụ lặp cho mỗi lần xây dựng, vì vậy nó không phải là một cách hợp lệ để xử lý danh sách trong trường hợp này.

Nhưng bạn có thể làm như sau:

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

Một lần nữa, sự phức tạp là O (n^2) trong trường hợp này.

+0

Vòng lặp đầu tiên hoạt động nếu anh ta thêm uber-gross "i--;" ở cuối câu lệnh if. –

+0

ý của bạn là gì? –

+0

Trong phiên bản cuối cùng, nó có xóa khỏi ArrayList hay chỉ từ trình lặp không? –

2

Tất cả câu trả lời hay. Nhưng tôi sẽ sugest bạn suy nghĩ lại. Ý tôi là, bạn có thực sự cần một ArrayList hoặc HashMap sẽ tốt hơn không? Nếu danh sách các đối tượng của bạn có khóa unic (ISBN), và bạn sử dụng nó để lấy từng đối tượng, tại sao không sử dụng một bộ sưu tập phù hợp cho vấn đề của bạn?

Bạn woud làm chỉ này

public void returnBook(String isbn){   
    Book book = (Book) booksBorrowed.remove(isbn);    
    book.returnBook();  
} 
Các vấn đề liên quan