web-dev-qa-db-ja.com

Java HashMapは反復中に新しいエントリを追加します

HashMapで

map = new HashMap<String,String>();

it = map.entrySet().iterator();
while (it.hasNext())
{
    entry = it.next();
    it.remove(); //safely remove a entry
    entry.setValue("new value"); //safely update current value
    //how to put new entry set inside this map
    //map.put(s1,s2); it throws a concurrent access exception

}

マップに新しいエントリを追加しようとすると、ConcurrentModificationExceptionがスローされます。削除と更新のために、イテレータには安全に削除するメソッドがあります。反復中に新しいエントリを追加するにはどうすればよいですか?

10
Burusothman

反復中にマップに値を設定することの意味を考慮する必要があります。 HashMapは、エントリが繰り返される順序を定義していません。したがって、新しいエントリを配置するときに、後でイテレータによってエントリが返されるかどうか。行動の一貫性は重要です。ただし、どちらの方法を選択した場合でも、既存のキーに新しい値を設定すると、動作に一貫性がなくなります。キーがすでに繰り返されている場合、変更は表示されず、キーがまだイテレータによって生成されていない場合に表示されます。

この問題を解決する簡単な方法は、新しいキーと値のペアの一時マップを作成し、反復の最後に一時マップをメインマップに追加することです。

Map<String,String> values = ...

Map<String,String> temp = new HashMap<>();
for (Entry<String,String> entry : values.entrySet()) {
    if ("some value".equals(entry.getValue()) {
        temp.put(entry.getValue(), "another value");
    }
}
values.putAll(temp);
7
Dunes

コレクションの反復中に要素を追加するには、ConcurrentHashMapを使用する必要があります。 HashMapはフェイルファストイテレーターを使用します。これは、反復中にコレクションが更新されるとConcurrentModificationExceptionをスローします。一方、ConcurrentHashMapはフェイルセーフイテレータを使用します。これは基本的に基になるコレクションのクローンで機能するため、反復中に変更できます。

2
Juned Ahsan

どうですか:

map = new HashMap<String,String>();

it = map.entrySet().iterator();
while (it.hasNext())
{
    entry = it.next();
    entry.setValue("new value"); // update current value
}

HashMapの実装を確認しましたが、このようなエントリを更新しても変更カウントは変更されません。また、これが許可されるべきではない理由もわかりません。何も削除されず、何も追加されず、キーも変更されません。

1
john16384