11

Java で Map を繰り返し処理しているとします...その Map を繰り返し処理しているときに、その Map に対して何ができるかわかりません。私は、Javadoc の Iterator インターフェイス remove メソッドの次の警告にほとんど混乱していると思います。

[...] このメソッドを呼び出す以外の方法で反復の進行中に基になるコレクションが変更された場合、反復子の動作は規定されていません。

remove メソッドを問題なく呼び出せることは確かです。しかし、Map コレクションを繰り返し処理しているときに、次のことができますか?

  1. キーに関連付けられた値を Map クラスの put メソッド (既存のキーで put) で変更しますか?

  2. Mapクラスのputメソッド(新しいキーでput)で新規エントリ追加?

  3. Map クラスの remove メソッドでエントリを削除しますか?

私の推測では、おそらく安全に #1 (既存のキーに配置) を実行できますが、#2 または #3 を安全に実行することはできません。

これについて明確にしていただきありがとうございます。

4

4 に答える 4

13

を使用できます。 Iterator.remove()(Map.Entry の) entrySet イテレーターを使用する場合は、 を使用できますMap.Entry.setValue()。それ以外のすべての賭けはオフです。マップを直接変更しないでください。一部のマップでは、前述の方法のいずれかまたは両方が許可されていません。

具体的には、(1)、(2)、(3) は認められません。

オブジェクトを介して既存のキーの値を設定することでうまくいくかもしれませんが、ドキュメントでは特にそれを除外しており、実装固有になります。MapSet.iterator()

セットに対する反復の進行中にマップが変更された場合 (反復子自体の削除操作、または反復子によって返されたマップ エントリに対する setValue 操作による場合を除く)、反復の結果は undefinedです。(強調追加)

于 2009-01-29T07:46:29.257 に答える
2

HashMap クラスを見ると、「modCount」というフィールドが表示されます。これは、反復中にいつ変更されたかをマップが認識する方法です。反復中に modCount をインクリメントするメソッドは、ConcurrentModificationException をスローします。

とはいえ、キーが既に存在する場合は値をマップに入れることができ、新しい値でエントリを効果的に更新できます。

 Map<String, Object> test = new HashMap<String, Object>();
 test.put("test", 1);

 for(String key : test.keySet())
 {
     test.put(key, 2); // this works!
 }

 System.out.println(test); // will print "test->2"

HashMap は、このような問題が発生するとすぐにその ConcurrentModificationException をスローするように設計されているため、これらの操作を「安全に」実行できるかどうかを尋ねても、あまり心配する必要はありません。これらの操作はすぐに失敗します。悪い状態でマップを離れることはありません。

于 2009-01-29T05:59:22.313 に答える
2

グローバルな答えはありません。マップ インターフェイスでは、ユーザーが選択できます。残念ながら、jdk のすべての実装はフェイルファスト実装を使用していると思います( HashMap Javadocに記載されているフェイルファストの定義は次のとおりです)。

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

于 2009-01-29T07:58:18.140 に答える
0

一般に、反復処理中に Map を変更する場合は、反復子のメソッドの 1 つを使用する必要があります。#1が機能するかどうかを実際にテストしたことはありませんが、他のものは間違いなく機能しません.

于 2009-01-29T05:22:20.703 に答える