1

現在、私のコードは断続的なConcurrentModificationExceptionエラーを引き起こしています。これは、おそらくHashMapをループしている方法が原因です。

for (Map.Entry<String, Entity> entry : entities.entrySet()) {
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        entities.remove(key);
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);
}
// updateInfo call
ViewManager.getInstance().updateInfo(summary());
}

どのようにしてHashMapを継続的にループし、ConcurrentModificationExceptionエラーを回避しますか?

4

5 に答える 5

5

ループ中にマップを変更することはできません。マップのコピーを作成するか、ConcurrentHashMapを使用するか、イテレータを使用する必要があります。マルチスレッド環境の場合は、同期ブロックで変更を行うことができます。

別のオプションは、イテレータを使用することです。

以下のイテレータを使用して、forループを書き直しました。

for(Iterator<Map.Entry<String, Entity>> iterator = entities.entrySet().iterator(); iterator.hasNext(); ){
    Map.Entry<String, Entity> entry = iterator.next();
    String key = entry.getKey();
    Entity item = entry.getValue();
    if (item.isDestroyed()){
        //Notice using an iterator to remove 
        iterator.remove();
        ViewManager.getInstance().removeItem(key);
        //INSTRUCT THE ENTITY TO PERFORM IT'S DESTROYED BEHAVIOR item.Destroyed()                    
    } else {
        item.update(1);
        ConsoleItem ci = new ConsoleItemImpl(item.getIdentifier(), item.getLocation(), ColorStringConverter.getInstance().StringToColor(item.getSide()), item.getAngle(), item.getShape(), item.toString(), item.isDestroyed(), item.isDamaged());
        ViewManager.getInstance().updateItem(ci);                    
    }

    item.update(1);

}

HashMapを継続的にループする部分についてはよくわかりません。ハッシュマップには有限のキーセットがあるため、通常はキーセットをループします。何らかの理由で継続的にループしたい場合は、最初にその背後にある理由と、その継続的なループの終了条件を教えてください(本当に永遠に続くことはできませんか?)。

于 2011-10-12T02:19:53.377 に答える
3

他の回答に記載されているように、for-eachループの代わりにIteratorベースのforループを使用することが、ConcurrentModificationExemptionsを回避するための最善の策です。無限ループについては、GuavaのIterators静的ユーティリティクラスのcycleメソッドをご覧ください。Iterable(HashMapなど)を受け取り、Iterableが空になるか、ループを解除するまでデータを継続的にループするIteratorを返します。

于 2011-10-12T02:58:48.207 に答える
1

イテレータとwhileループを使用するのはどうですか?

Iterator<String> iterator = map.iterator();
String key;
String value;
while (iterator.hasNext()) {
 key = iterator.next();
 value = map.get(key);
}
于 2011-10-12T02:25:56.673 に答える
1

ループ中にremote(key)メソッドを呼び出すことはできませんが、イテレータを介してエントリを削除することはできます。

Map<String, String> map = new HashMap<String, String>();
map.put("one", "1");
map.put("two", "2");
map.put("three", "3");

for (Iterator<Map.Entry<String, String>> i = map.entrySet().iterator(); i.hasNext();)
{
    Map.Entry<String, String> curEntry = i.next();
    if (curEntry.getKey().equals("two"))
        i.remove();
}
于 2011-10-12T02:28:54.643 に答える
0

スレッド上でのみマップにアクセスしていると仮定すると、他の人が示唆しているように、イテレータを使用します。

ハッシュマップを反復処理するときのパフォーマンスについて考えていたので、ConcurrentHashMap、HashMap、LinkedHashMap、TreeMapなどのさまざまなマップ実装を使用して、10 ^ 6のランダムなLongsで25回の反復を行い、その10%を削除するクイックテストを行いました。

リンクされたハッシュマップは、おそらく反復用に調整されており、最も効率的であるように思われます。スパイクはgcによるものだと思います。

...しかし、違いは私が予想していたよりも小さいです。

ここに画像の説明を入力してください

于 2011-10-12T06:55:21.233 に答える