13 Stimmen

Iterator auf einem TreeSet verwenden

SITUATION: Ich habe ein TreeSet von benutzerdefinierten Objekten und ich habe auch einen benutzerdefinierten Comparator verwendet. Ich habe einen Iterator erstellt, der in diesem TreeSet verwendet wird.

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
}

PREGUNTA: Nun, ich möchte wissen, dass, wenn ich ein neues Element zum TreeSet innerhalb der while-Schleife hinzufügen, dann wird dieses neue Element sofort sortiert werden. Mit anderen Worten, wenn ich ein neues Element innerhalb der while-Schleife hinzufüge und es kleiner ist als das, das ich gerade in c halte, werde ich dann in der nächsten Iteration das gleiche Element in c bekommen wie in der letzten Iteration? (da das neu hinzugefügte Element nach der Sortierung einen Platz irgendwo vor dem aktuellen Element einnehmen wird).

24voto

Michael Brewer-Davis Punkte 13669

Wenn Sie während Ihrer Iteration ein Element hinzufügen, wird Ihr nächster Iteratoraufruf wahrscheinlich ein ConcurrentModificationException . Siehe das ausfallsichere Verhalten in TreeSet docs.

Um Elemente zu iterieren und hinzuzufügen, können Sie zunächst in eine andere Menge kopieren:

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

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

// continue, using tsWithExtra

oder eine separate Sammlung erstellen, die mit ts nach der Iteration, wie Colin vorschlägt.

7voto

anubhava Punkte 713155

Sie erhalten eine java.util.ConcurrentModificationException wenn Sie innerhalb der while-Schleife ein Element in das TreeSet einfügen.

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");
}

Salida

Exception in thread "main" java.util.ConcurrentModificationException

3voto

NILESH SALPE Punkte 145
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

Dies gilt für alle Sammlungen wie List , Map , Set Denn wenn der Iterator startet, kann es sein, dass er eine Sperre anlegt.

wenn Sie Liste mit Iterator iterieren, dann wird diese Ausnahme kommen. Ich denke, sonst diese Schleife wird unendlich sein, wie Sie Element ganze Iteration hinzufügen.

Ohne Iterator betrachten:

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());
}

Das wird schon klappen.

1voto

kriegaex Punkte 56700

Zur Vermeidung der ConcurrentModificationException dann sollten Sie sich vielleicht meine UpdateableTreeSet . Ich habe sogar eine neue Testfall zeigt, wie man Elemente während einer Schleife hinzufügen kann. Genauer gesagt, Sie markieren neue Elemente für eine spätere, zeitversetzte Aktualisierung der Menge. Das funktioniert recht gut. Im Grunde tun Sie etwas wie

for (MyComparableElement element : myUpdateableTreeSet) {
    if (someCondition) {
        // Add new element (deferred)
        myUpdateableTreeSet.markForUpdate(
            new MyComparableElement("foo", "bar", 1, 2)
        );
    }
}

// Perform bulk update
myUpdateableTreeSet.updateMarked();

Ich denke, das ist ziemlich genau das, was Sie brauchen. :-)

0voto

Houcheng Punkte 2366

Um die ConcurrentModificationException beim Laufen zu verhindern. Unten ist meine Version, um hochfrequentes Einfügen in das TreeSet() zu ermöglichen und gleichzeitig darauf zu iterieren. Diese Klasse verwendet eine zusätzliche Warteschlange, um das einzufügende Objekt zu speichern, wenn das TreeSet iteriert wird.

public class UpdatableTransactionSet {
TreeSet <DepKey> transactions = new TreeSet <DepKey> ();
LinkedList <DepKey> queue = new LinkedList <DepKey> ();
boolean busy=false;
/**
 * directly call it
 * @param e
 */
void add(DepKey e) {
    boolean bb = getLock();
    if(bb) {
        transactions.add(e);
        freeLock();
    } else {
        synchronized(queue) {
            queue.add(e);
        }
    }
}
/**
 * must getLock() and freeLock() while call this getIterator function
 * @return
 */
Iterator<DepKey> getIterator() {
    return null;
}

synchronized boolean getLock() {
    if(busy) return false;
    busy = true;
    return true;
}
synchronized void freeLock() {
    synchronized(queue) {
        for(DepKey e:queue) {
            transactions.add(e);
        }
    }       
    busy = false;
}
}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X