2012-04-01 5 views
5

меня проблема с удалением объекта из ArrayList при работе над заданием Если я использую «нормальный» цикл, он работает следующим образомУдаление 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);     
     } 
    } 
} 

Однако, когда я пытаясь упростить код с расширенным для цикла, который не работает и показывает java.util.ConcurrentModificationException ошибки:

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

Надеется, что вы, ребята, могли бы облегчить мне ..

+0

Если ваш вопрос «Почему я получаю сообщение об ошибке» это потому что вы не можете удалить элементы из списка, который вы повторяете. И ваш первый цикл может иметь ошибку в нем, если тот же ISBN может быть в списке дважды. –

ответ

7

ваших альтернативы, чтобы избежать 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"))); 

Соберите все записи, которые вы хотите удалить на улучшенном цикл, и после того, как вы закончите перебор , вы удаляете все найденные записи.

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, который имеет поддержку способа удалить во время самой итерации.

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

+0

Ты спасаешь мою жизнь. благодаря –

4

Вы действительно не должны делать то, что они вызовут проблемы в конце. Вместо этого используйте итератор ArrayList, чтобы помочь вам выполнить итерацию по списку, а затем удалить только с помощью итератора. Это поможет предотвратить пагубные ошибки одновременной модификации.

+1

/golfclap использование 'pernicious' –

0

Когда вы используете расширенный цикл for-loop в Java, он использует итератор списка для перебора по списку. Когда вы удаляете элемент с функцией удаления из списка, это будет мешать состоянию итератора, и итератор будет вызывать исключение ConcurrentModificationException. С помощью простого для цикла у вас нет такой проблемы, потому что вы используете только этот список, а изменение состояния происходит только в самом списке.

+0

Поучитесь немного рассказать о том, как использовать итератор для удаления объекта Book – babygau

+0

Это действительно зависит от того, что вы используете, и какого рода производительность вы хотите. Комбинация hashmap и итератора arraylist сделает это. – amshali

1

У Вас есть ошибка в вашем коде:

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

Он пропускает следующие элементы после устраненных. Например. когда вы удаляете элемент «0-й», 1-й становится 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 (Iterator<String> i = a.iterator(); i.hasNext();) { 
     Book next = i.next(); 
     if (book.getISBN() == isbn){ 
      book.returnBook(); 
      i.remove(i);     
     } 
    } 

Опять же, сложность O (N^2) в этом случае.

+0

Первый цикл работает, если он добавляет uber-gross "i--;" в нижней части оператора if. –

+0

Что значит? –

+0

В последнем ли это удаление из ArrayList или только из итератора? –

2

Все хорошие ответы. Но я бы попросил вас переосмыслить его. Я имею в виду, вам действительно нужен ArrayList или HashMap будет лучше? Если ваш список объектов имеет единый ключ (ISBN), и вы используете его для получения каждого объекта, почему бы не использовать коллекцию, предназначенную для вашей проблемы?

Вы woud сделать это только

public void returnBook(String isbn){   
    Book book = (Book) booksBorrowed.remove(isbn);    
    book.returnBook();  
} 
Смежные вопросы