2012-04-01 9 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);     
     } 
    } 
} 

を次のように動作しますforループ強化では動作しませんので、コードを単純化しようとしていると示すjava.util.ConcurrentModificationExceptionがエラー:

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

は君たちが私を明るくことを願っています。..

+0

あなたの質問は、それがある「にエラーが発生するのはなぜか」された場合反復処理中のリストから項目を削除することはできないためです。同じISBNがリストに2回含まれている場合は、最初のループにバグがある可能性があります。 –

答えて

7

あなたの選択肢を行うwoud

は以下のとおりです。

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

それとも、反復自体の間removeメソッドをサポートしてい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ループをJavaで使用している場合は、リストの反復処理を使用してリストを反復処理します。リストのremove関数を使用して項目を削除すると、イテレーターの状態を妨げ、イテレーターはConcurrentModificationExceptionをスローします。 単純なfor-loopでは、リストを使用しているだけなので、そのような問題はなく、状態の変更はリスト自体でのみ発生します。

+0

Bookオブジェクトを削除するためにイテレータを使用する方法を少し教えてください。 – babygau

+0

それは本当にあなたのアプリケーションとあなたが望むようなパフォーマンスに依存します。ハッシュマップとarraylistイテレータを組み合わせると、それが実行されます。 – amshali

1

あなたはあなたのコードのバグを持っている:

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

最初のループは、彼がuber-gross "i--;" if文の一番下にあります。 –

+0

どういう意味ですか? –

+0

最後の1つでは、ArrayListかイテレータからのみ削除されますか? –

2

すべての良い答え。しかし、私はあなたにそれを再考することをお勧めします。つまり、本当にArrayListが必要なのですか?HashMapは良いでしょうか?オブジェクトのリストにユニコードキー(ISBN)があり、それを使って各オブジェクトを取得する場合は、問題に適したコレクションを使用してください。あなたはConcurrentModificationExceptionを回避する唯一のこの

public void returnBook(String isbn){   
    Book book = (Book) booksBorrowed.remove(isbn);    
    book.returnBook();  
} 
関連する問題