1

以下のようなベクトルからリストを削除しようとしました。

public class StringVectorTest {

private final List<String> stringVector = new Vector<String>();

@Test
public void listRemoveTest(){

    List<String> list = stringVector.subList(0, 2);

    stringVector.removeAll(list);

    Assert.assertEquals(stringVector.size(), 3);
}

@Before
public void fillList(){
    stringVector.add("ABC");
    stringVector.add("DEF");
    stringVector.add("GEH");
    stringVector.add("IJK");
    stringVector.add("LMN");
}

}

テストを実行しているときに、以下のエラーが発生します

java.util.ConcurrentModificationException
at java.util.SubList.checkForComodification(AbstractList.java:752)
at java.util.SubList.listIterator(AbstractList.java:682)
at java.util.AbstractList.listIterator(AbstractList.java:284)
at java.util.SubList.iterator(AbstractList.java:678)
at java.util.AbstractCollection.contains(AbstractCollection.java:82)
at java.util.Collections$SynchronizedCollection.contains(Collections.java:1563)
at java.util.AbstractCollection.removeAll(AbstractCollection.java:336)
at java.util.Vector.removeAll(Vector.java:853)

Iteratorこれを克服するには、を使用する必要があることを知っていConcurrentModificationExceptionます。効率的な方法/ベストプラクティスでどのように使用するかを教えてください。

前もって感謝します。

4

2 に答える 2

3

以下のようにしてください:

public void listRemoveTest() {
    stringVector.subList(0, 2).clear();
    Assert.assertEquals(stringVector.size(), 3);
}
于 2012-04-28T06:05:54.127 に答える
2

ConcurrentModificationExceptionのjavadocから:

この例外は、オブジェクトの同時変更が許可されていない場合に、そのような変更を検出したメソッドによってスローされる可能性があります。たとえば、別のスレッドがコレクションを反復処理しているときに、あるスレッドがコレクションを変更することは一般的に許可されていません。一般に、これらの状況では、反復の結果は定義されていません。一部のIterator実装(JREによって提供されるすべての汎用コレクション実装の実装を含む)は、この動作が検出された場合にこの例外をスローすることを選択する場合があります。これを行うイテレータは、将来の不確定な時間に任意の非決定論的な動作のリスクを冒すのではなく、迅速かつクリーンに失敗するため、フェイルファストイテレータと呼ばれます。

この例外は、オブジェクトが別のスレッドによって同時に変更されたことを常に示しているわけではないことに注意してください。単一のスレッドがオブジェクトのコントラクトに違反する一連のメソッド呼び出しを発行した場合、オブジェクトはこの例外をスローする可能性があります。たとえば、スレッドがフェイルファストイテレータを使用してコレクションを反復処理しているときにコレクションを直接変更すると、イテレータはこの例外をスローします。

後者はまさにあなたがしていることです(あなたが投稿したスタックトレースを参照してください)。subListメソッドはリストのビューを返すため、このメソッドから返されたリストは、によってサポートされますstringVector。したがって、返されたリストの非構造的な変更はに反映されstringVector、その逆も同様です。

したがって、この「ビュー」を使用して要素を削除する必要があります。

@Test
public void listRemoveTestClearingSubList(){
    stringVector.subList(0, 2).clear();    
    Assert.assertEquals(stringVector.size(), 3);
}

イテレータを使用すると、少しトリッキーで醜いためです。

@Test
public void listRemoveTestClearingWithIterator(){
    Iterator<String> it = stringVector.iterator();
    for (int i = 0; i < 2 && it.hasNext(); i++) {
        it.next();
        it.remove();
    }

    Assert.assertEquals(stringVector.size(), 3);
}   
于 2012-04-28T06:14:47.303 に答える