6

私は2つHashMap<Integer,Point3D>のオブジェクト名を持っていますpositiveCoOrdinate and negativeCoOrdinates.

PositiveCoOrdinates以下の条件でチェックnegativeCoOrdinatesしていますpositiveCoOrdinates

  HashMap<Integer, Point3d> positiveCoOrdinates=duelList.get(1);
  HashMap<Integer, Point3d> negativecoOrdinates=duelList.get(2);
  //condition
  Set<Integer> set=positiveCoOrdinates.keySet();
    for (Integer pointIndex : set) {
        Point3d coOrdinate=positiveCoOrdinates.get(pointIndex);
        if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) {
            negativecoOrdinates.put(pointIndex, coOrdinate);
            positiveCoOrdinates.remove(pointIndex);
        }
    }

時間を追加、削除しているときに、次のエラーが発生します。

 Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at PlaneCoOrdinates.CoordinatesFiltering.Integration(CoordinatesFiltering.java:167)
at PlaneCoOrdinates.CoordinatesFiltering.main(CoordinatesFiltering.java:179)

私のテストでは、条件System.out.println(coOrdinate.x);内のステートメントについて言及します。正常に機能しています。If

条件内に2行(上記で述べたもの)を追加するとIf、エラーがスローされます。

どうすればこれを修正できますか。

ありがとう。

4

4 に答える 4

11

最も簡単な方法は、keySet のコピーを作成することです。

  Set<Integer> set= new HashSet<Integer>(positiveCoOrdinates.keySet());

この問題は、キーを反復処理するpositiveCoOrdinatesを使用しているときに を変更しているために発生します。Iterator

コードをリファクタリングして、エントリ セットに対して反復子を使用することもできます。これはより良いアプローチです。

Set<Entry<Integer, Point3d>> entrySet = positiveCoOrdinates.entrySet();

    for (Iterator<Entry<Integer, Point3d>> iterator = entrySet.iterator(); iterator.hasNext();) {
        Entry<Integer, Point3d> entry = iterator.next();
        Point3d coOrdinate = entry.getValue();
        if (coOrdinate.x > xMaxValue || coOrdinate.y > yMaxValue
                || coOrdinate.z > zMaxValue) {
            Integer pointIndex = entry.getKey();
            negativecoOrdinates.put(pointIndex, coOrdinate);
            iterator.remove();
        }
    }
于 2013-10-01T11:05:04.880 に答える
2

拡張ループremove()を使用する場合、反復コレクションからはできません。ループは暗黙的にfor-each使用します。JavaDocは明確に次のように述べていますfor-eachIterator<Integer>

このクラスのすべての「コレクション ビュー メソッド」によって返されるイテレータはフェイルファストです。イテレータの作成後にマップが構造的に変更された場合、イテレータ自体のメソッド以外のremove()方法で、イテレータは ConcurrentModificationException. したがって、同時変更に直面した場合、反復子は、将来の不確定な時点で恣意的で非決定論的な動作を危険にさらすのではなく、迅速かつ明確に失敗します。

for-eachループは内部で反復子を作成し、それを使用してセットをトラバースします。次に、セットの構造を変更します...そしてイテレータは失敗する必要があります。問題は、反復子のメソッドにアクセスできないため、Iterator<Integer>明示的に使用する必要があることです。生成されたトラバース バイトコードは同じですが、唯一の違いは、リストをトラバースするときにリストから要素を削除できることです。

Set<Integer> set = positiveCoOrdinates.keySet();
for (Iterator<Integer> iterator = set.iterator(); iterator.hasNext(); ) {
    Integer pointIndex = iterator.next();
    Point3d coOrdinate = positiveCoOrdinates.get(pointIndex);
    if (coOrdinate.x>xMaxValue || coOrdinate.y>yMaxValue || coOrdinate.z>zMaxValue) {
        negativecoOrdinates.put(pointIndex, coOrdinate);
        iterator.remove(pointIndex);    // this line changed!
    }
}

イテレータとその機能に慣れていない場合は、Collections に関する Oracle のチュートリアルを参照してください。

AnIteratorは、必要に応じてコレクションを走査し、コレクションから要素を選択的に削除できるようにするオブジェクトです。Iteratorメソッドを呼び出すことで、コレクションの を取得しますiterator()

Iterator.remove()反復中にコレクションを変更する唯一の安全な方法であることに注意してください。反復の進行中に基になるコレクションが他の方法で変更された場合、動作は規定されていません。

次の必要がある場合Iteratorは、構文の代わりに使用します。for-each

  • 現在の要素を削除します。このfor-each構造は反復子を隠しているため、 を呼び出すことはできませんremove()。したがって、このfor-each 構文はフィルタリングには使用できません。
于 2013-10-01T11:12:03.173 に答える
0

René によって指摘されているように、この非常に一般的な問題の理由は、別のコレクションが読み取られている間にコレクションが同時に変更されることです。

ConcurrentHashMapやCopyOnWriteArrayLitのようなコレクションを使用できますが、これらのアプローチは少し高価であり、同じコレクションの読み取りを排除するためにコードを変更する単純なチェンジャーであることに注意してください。反復では、このタイプの問題が解決されます。

于 2013-10-01T11:34:29.690 に答える
0

Iterator実行時にコレクションを変更する場合は、強化された for ループの代わりに使用する必要があります。強化された for ループは読み取り専用機能のみを提供するためです。以下は反復子の例です。

Iterator<Entity> iterator = collection.Iterator();
while(iterator.hasNext()){
  //DO Your Stuff
  iterator.remove(); // this function call remove the element from collection at run time
}
于 2013-10-01T11:11:30.670 に答える