11

状況:カスタム オブジェクトの TreeSet があり、カスタム Comparator も使用しています。この TreeSet で使用する反復子を作成しました。

TreeSet<Custom> ts=new TreeSet<Custom>();
Iterator<Custom> itr=ts.iterator();
while(itr.hasNext()){
    Custom c=itr.next();
    //Code to add a new element to the TreeSet ts
}

質問: while ループ内で TreeSet に新しい要素を追加すると、その新しい要素はすぐに並べ替えられるかどうかを知りたいです。つまり、while ループ内に新しい要素を追加し、それが現在 c で保持している要素よりも小さい場合、次の反復では、最後の反復と同じ要素を c で取得することになりますか?(並べ替えの後、新しく追加された要素は現在の要素の前の場所を占有するためです)。

4

7 に答える 7

24

反復中に要素を追加すると、次のイテレータ呼び出しでがスローされる可能性がありConcurrentModificationExceptionます。TreeSetドキュメントのフェイルファスト動作を参照してください。

要素を繰り返して追加するには、最初に別のセットにコピーします。

TreeSet<Custom> ts = ...
TreeSet<Custom> tsWithExtra = new TreeSet(ts);

for (Custom c : ts) {
  // possibly add to tsWithExtra
}

// continue, using tsWithExtra

tsまたは、Colinが提案するように、反復後にマージする別のコレクションを作成します。

于 2011-06-23T20:39:29.043 に答える
6

while ループ内の TreeSet に要素を追加すると、java.util.ConcurrentModificationExceptionが発生します。

Set<String> ts=new TreeSet<String>();
ts.addAll(Arrays.asList(new String[]{"abb", "abd", "abg"}));
Iterator<String> itr=ts.iterator();
while(itr.hasNext()){
    String s = itr.next();
    System.out.println("s: " + s);
    if (s.equals("abd"))
        ts.add("abc");
}

出力

Exception in thread "main" java.util.ConcurrentModificationException
于 2011-06-23T20:43:48.267 に答える
3
public static void main(String[] args) {
    TreeSet<Integer> ts=new TreeSet<Integer>();
    ts.add(2);
    ts.add(4);
    ts.add(0);

    Iterator<Integer> itr=ts.iterator();
    while(itr.hasNext()){
        Integer c=itr.next();
        System.out.println(c);
        //Code
        ts.add(1);
    }
}


Exception in thread "main" java.util.ConcurrentModificationException

Listこれは,のようなすべてのコレクションに適用されます。これはMapSet イテレータの開始時に何らかのロックが設定されている可能性があるためです。

イテレータを使用してリストを反復すると、この例外が発生します。そうしないと、要素全体の反復を追加しているため、このループは無限になると思います。

イテレータなしで考えてみましょう:

public static void main(String[] args) {
    List<Integer> list=new ArrayList<Integer>();
    list.add(2);
    list.add(4);
    list.add(0);

    for (int i = 0; i < 3; i++) {
        System.out.println(list.get(i));
        list.add(3);
    }
    System.out.println("Size" +list.size());
}

これで大丈夫です。

于 2011-06-23T21:02:07.477 に答える
0

質問はすでに回答されていますが、最も満足のいく回答はTreeSet自体の javadoc にあると思います

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

イテレータのフェイルファスト動作はそのままでは保証できないことに注意してください。 >一般的に言えば、同期されていない同時変更が存在する場合にハードな保証を行うことは不可能です。フェイルファスト イテレーターは、ベスト エフォート ベースで ConcurrentModificationException をスローします。したがって、その正確性をこの例外に依存するプログラムを作成するのは誤りです。反復子のフェイルファスト動作は、バグを検出するためだけに使用する必要があります。

于 2015-01-16T07:05:10.520 に答える