Betrachten Sie den folgenden Code-Schnipsel:Warum keine ConcurrentModificationException in dieser Situation mit LinkedList-Iterator?
List<String> list = new LinkedList<>();
list.add("Hello");
list.add("My");
list.add("Son");
for (String s: list){
if (s.equals("My")) list.remove(s);
System.out.printf("s=%s, list=%s\n",s,list.toString());
}
Dies resultiert in der Ausgabe:
s = Hallo, list = [Hallo, mein, Sohn]
s = My, list = [Hallo, Sohn]
So deutlich wurde die Schleife nur zweimal eingegeben, und das dritte Element, "Son", wird nie besucht. Aus dem zugrunde liegenden Bibliothekscode sieht es so aus, als ob die hasNext()
-Methode im Iterator nicht nach gleichzeitiger Änderung sucht, sondern nur nach der Größe gegenüber dem nächsten Index. Da die Größe durch den Aufruf remove()
um 1 reduziert wurde, wird die Schleife einfach nicht erneut eingegeben, aber es wird keine ConcurrentModificationException ausgelöst.
Dies scheint den Vertrag des Iterators zu widersprechen:
Die Liste-Iterator ist ausfall schnell: wenn die Liste strukturell jederzeit geändert, nachdem der Iterator, außer in irgendeiner Weise erstellt wird Durch die eigenen Methoden
remove
oderadd
des Listen-Iterators wirft der Listen-Iterator eineConcurrentModificationException
. Angesichts der gleichzeitigen Modifikation versagt der Iterator daher schnell und sauber, anstatt willkürliches, nicht-deterministisches Verhalten zu einem unbestimmten Zeitpunkt in der Zukunft zu riskieren.
Ist das ein Fehler? Auch hier scheint der Vertrag des Iterators definitiv nicht befolgt zu werden - die Struktur der Liste wird strukturell durch etwas anderes als den Iterator in der Mitte der Iteration modifiziert.
Einige Leute verweisen auf die Dokumentation der LinkedList-Klassenebene, die einige Hinweise darauf gibt, dass die ConcurrentModificationException auf "Best Effort" -Basis ist. Es sei denn, jemand kann beweisen, warum das Hinzufügen zu "hasNext()" aus irgendeinem Grund problematisch ist, es scheint nicht die beste Anstrengung überhaupt zu sein. – PeteyPabPro
Ich könnte hier das Offensichtliche angeben, aber der einzige Grund, warum ich mir vorstellen kann, die Prüfung für die Änderung in der 'hasNext()' Methode nicht zu implementieren, ist, dass es eine Verdoppelung der Prüfvorgänge in * allen * Fällen während Abwesenheit garantiert Eine solche Überprüfung führt nur in einigen Fällen zum Nicht-Auslösen der Ausnahme, wenn die durchgeführte Änderung zum sofortigen Verlassen der Schleife führt (z. B. wenn alle Elemente von der aktuellen Position des Iterators bis zum Ende des Containers entfernt werden). , was von den Implementierern als relativ selten angesehen wurde. –
Scheint ein Duplikat von http://stackoverflow.com/questions/14673653/why-isnt-this-code-causing-a-concurrentmodificationexception?lq=1 (wie in einer Antwort) – Marco13