@Eran hat bereits erklärt , wie man dieses Problem besser lösen kann. Ich werde erklären, warum ConcurrentModificationException
auftritt.
Das ConcurrentModificationException
tritt auf, weil Sie die Stream-Quelle ändern. Ihr Map
ist wahrscheinlich HashMap
oder TreeMap
oder eine andere nicht gleichzeitige Karte. Nehmen wir an, es ist ein HashMap
. Jeder Stream wird von Spliterator
unterstützt. Wenn der Spliterator keine Eigenschaften IMMUTABLE
und CONCURRENT
hat, lautet die Dokumentation wie folgt:
Nach der Bindung sollte ein Spliterator auf bestmöglicher Basis
ConcurrentModificationException
werfen, wenn strukturelle Interferenzen erkannt werden. Spliter, die dies tun, werden fail-fast genannt.
Also ist das HashMap.keySet().spliterator()
nicht IMMUTABLE
(weil dieses Set
geändert werden kann) und nicht CONCURRENT
(gleichzeitige Updates sind für HashMap
unsicher). Daher werden nur die gleichzeitigen Änderungen erkannt und ein ConcurrentModificationException
ausgegeben, wie es die Dokumentation für den Spliterator vorschreibt.
Es lohnt sich auch, die Die Iteratoren, die von allen "Auflistungsansichtsmethoden" dieser Klasse zurückgegeben werden, sind fail-fast : wenn die Map zu irgendeinem Zeitpunkt nach der Erstellung des Iterators strukturell modifiziert wird, außer durch den Iterator eigene Methode entfernen, wirft der Iterator eine Beachten Sie, dass das Fail-Fast-Verhalten eines Iterators nicht garantiert werden kann, da es im Allgemeinen unmöglich ist, bei unsynchronisierten simultanen Modifikationen harte Garantien zu geben. Fail-Fast-Iteratoren werfen Obwohl es nur über Iteratoren aussagt, glaube ich, dass es bei Spliteratoren genauso ist. HashMap
Dokumentation
ConcurrentModificationException
. 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. ConcurrentModificationException
auf Best-Effort-Basis. Daher wäre es falsch, ein Programm zu schreiben, das für seine Korrektheit von dieser Ausnahme abhing: Das Fail-Fast-Verhalten von Iteratoren sollte nur zum Aufspüren von Fehlern verwendet werden .
Ihr Stream-Aufruf führt (logisch) Folgendes aus:
%Vor% Wenn Sie dies ausführen, wird es ConcurrentModificationException
ausgeben, weil es die Karte zur gleichen Zeit verändert, wenn Sie darüber iterieren. Wenn Sie sich die Dokumentation ansehen, werden Sie Folgendes bemerken:
Beachten Sie, dass diese Ausnahme nicht immer anzeigt, dass ein Objekt gleichzeitig von einem anderen Thread geändert wurde. Wenn ein einzelner Thread eine Sequenz von Methodenaufrufen ausgibt, die den Vertrag eines Objekts verletzen, kann das Objekt diese Ausnahme auslösen. Wenn beispielsweise ein Thread eine Auflistung direkt ändert, während sie die Auflistung mit einem Fail-Fast-Iterator wiederholt, löst der Iterator diese Ausnahme aus.
Dies ist, was Sie tun, die Map-Implementierung, die Sie verwenden, hat offensichtlich schnelle Iteratoren, daher wird diese Ausnahme ausgelöst.
Eine mögliche Alternative besteht darin, die Elemente mit dem Iterator direkt zu entfernen:
%Vor%Tags und Links java lambda hashmap foreach java-stream