Frage
Ich muss nicht spezifizierte Elemente aus der ersten Sammlung aus einer Sammlung von Java entfernen, basierend auf dem Inhalt einer anderen Sammlung. Das sieht sehr einfach aus, ist aber ein Problem.
Dies ist der Kopf der Methode, die ich schreiben möchte
private void screenblacknamelist (Liste <SharedboardsMswrapper> Quelle, Liste <BlacknamelistModel> Blacknamelist)
So sind die Dinge. Die Quellsammlung speichert einige Anzeigedatenelemente. Die Blacknamelist -Sammlung spart eine Blacklist -Liste. Wir müssen die Daten der Blacklisted -Benutzer in der Quellsammlung basierend auf der Blacklist -Tabelle entfernen.
Die Lösung für dieses Problem scheint sehr einfach.
Ich benutze zuerst die für jede Anweisung zum Löschen.
for(SharedBoardSmsWrapper tmpSharedBoardSmsWrapper:source){ for(BlackNameListModel tmpBlackNameListModel:blackNameList){ if(tmpSharedBoardSmsWrapper.getSource().equals(tmpBlackNameListModel.getSource())){ Source.Remove (tmpSharedBoardsMswrapper); brechen; }}}Sehr einfache Frage! Ich lachte heimlich,
prüfen…
Was mich überrascht hat, war, dass dieser Code tatsächlich eine Ausnahme gemacht hat
java.util.ConcurrentModificationException。
JDK6 -Handbuch anzeigen
öffentliche Klasse ConcurrentModificationExceptionends RunTimeException
Diese Ausnahme wird ausgelöst, wenn die Methode eine gleichzeitige Modifikation des Objekts erkennt, jedoch keine solche Änderung zulässt.
Wenn beispielsweise ein Thread in einer Sammlung iteriert, darf eine andere Sammlung nicht linear modifiziert werden. Normalerweise sind in diesen Fällen die Ergebnisse der Iteration ungewiss. Wenn dieses Verhalten erkannt wird, können einige Iterator -Implementierungen (einschließlich aller von JRE bereitgestellten gemeinsamen Sammlungsimplementierungen ) diese Ausnahme ausführen. Der Iterator, der diesen Vorgang ausführt, wird als Iterator für schnelles Ausfall als Iterator bezeichnet, da der Iterator sehr schnell fehlschlägt, ohne das Risiko eines willkürlichen ungewöhnlichen Verhaltens zu einem bestimmten Zeitpunkt in der Zukunft zu riskieren.
Beachten Sie, dass diese Ausnahme nicht immer darauf hinweist, dass das Objekt gleichzeitig durch einen anderen Thread geändert wurde. Wenn ein einzelner Thread eine Abfolge von Methodenaufrufen ausgibt, die gegen den Vertrag des Objekts verstoßen, kann das Objekt diese Ausnahme ausführen. Wenn beispielsweise ein Thread die Sammlung direkt ändert, wenn die Sammlung mit einem schnellen Iterator iteriert, wird der Iterator diese Ausnahme ausgelöst.
Beachten Sie, dass das schnelle Versagensverhalten des Iterators nicht garantiert werden kann, da es im Allgemeinen unmöglich ist, eine harte Garantie dafür zu erhalten, ob es eine nicht synchrone Änderung gibt. Eine schnelle Ausfalloperation wird sein Bestes tun, um ConcurrentModificationException zu werfen. Daher ist es falsch, ein Programm zu schreiben, das von dieser Ausnahme abhängt, um die Richtigkeit solcher Operationen zu verbessern. Der richtige Weg ist : ConcurrentModificationException sollte nur zum Erkennen von Fehler verwendet werden.
For each in Java verwendet tatsächlich Iterator zur Verarbeitung. Durch Iterator können Kollektionen während der Verwendung von Iterator nicht gelöscht werden. Und als ich for each war, habe ich ein Element aus der Sammlung gelöscht, das den Iterator veranlasste, ConcurrentModificationException zu werfen.
Es scheint, dass wir das traditionelle für Loop nur ehrlich verwenden können!
für (int i = 0; i <source.size (); i ++) {SharedBoardsMswrapper tmpSharedBoardsMswrapper = source.get (i); für (int j = 0; j <Blacknamelist.size (); j ++) {BlacknamelistModel TMPBlacknamelistModel = Blacknamelist.get (j); if (tmpSharedBoardsMswrapper.getSource (). Equals (tmpblacknamelistModel.getSource ()) {Source.Remove (tmpSharedBoardsMswrapper); brechen; }}}Es sollte jetzt in Ordnung sein! Drücken Sie den Test mit Zuversicht ...
schwach! Was ist los? Wie können die Daten falsch gefiltert werden?
Nach dem Debug -Tracking wurde festgestellt, dass die Größe des Satzes, wenn der Satz Elemente löscht, kleiner wird und sich der Index ändert!
Was soll ich tun? Ich werde von einem so kleinen Problem nicht hilflos sein!
Verwenden Sie Iterator, um Elemente in der Sammlung zu löschen
Überprüfen Sie die Iterator -Schnittstelle des JDK -Handbuchs und sehen Sie, dass es auch über eine Entfernungsmethode verfügt.
Entfernen
Hohlraum entfernen ()
Entfernen Sie das letzte vom Iterator zurückgegebene Element aus der Sammlung, auf die der Iterator (optionaler Vorgang) gerichtet ist. Diese Methode kann nur einmal pro Anruf als nächstes aufgerufen werden. Wenn der Iterator durch eine Sammlung geändert wird, auf die der Iterator mit einer anderen Methode als dieser Methode aufgerufen wird, ist das Verhalten des Iterators ungewiss.
Werfen:
UnsupportedOperationException - Wenn der Iterator den Betrieb nicht entfernen .
IllegalStateException - Wenn die nächste Methode nicht aufgerufen wurde oder die Entfernungsmethode nach dem letzten Aufruf zur nächsten Methode aufgerufen wurde.
Richtiger endgültiger Code:
/ ** *@paramSource *@paramblacknamelist */ privatVoid screenblacknamelist (Liste <SharedBoardsMSWRapper> Quelle, Liste <BlacknamelistModel> Blacknamelist) {Iterator <SaredBoardsMswrapper> Sourceit = Source.iterator (); while (socalit.hasnext ()) {SharedBoardsMSWRapper tmpSharedBoardsMswrapper = SourceIt.Next (); Iterator <BlacknamelistModel> Blacknamelistit = Blacknamelist.Iterator (); while (Blacknamelistit.hasnext ()) {BlacknamelistModel tmpblacknamelistModel = Blacknamelistit.Next (); if (tmpSharedBoardsMswrapper.getSource (). Equals (tmpblacknamelistModel.getSource ()) {Sourceit.remove (); brechen; }}}}} Beachten Sie, dass die next() remove() des Iterators nicht mehrmals aufgerufen werden kann. Andernfalls wird eine Ausnahme geworfen.
Es scheint, dass der einfachste Weg, Elemente in einer Sammlung zu löschen, darin besteht, die Iterator remove() zu verwenden!
Lassen Sie uns sehen, wie der von der ArrayList -Klasse bereitgestellte Iterator implementiert wird.
PrivateClass ITR implementiert Iterator <E> { /** Dies ist der Index des Elements, der einem Zeiger oder Cursor entspricht, der es verwendet, um auf das Datenelement der Liste zuzugreifen. *INDEXOFELEMENTOBERETURNEDBYSBYSUBESTCALLToneXT. */ intcursor = 0; /** *IndexoFelementReturnedByMostrecentCallTonextor *vorher. Resetto -1FeTHiSElementisDeletedByAcall *Toremove. 最新元素的索引。 Wenn das Element gelöscht wurde, auf -1 */ intlastret = -1 eingestellt; /** Eigenschaften der externen KlassenarrayList: Protected Transient int modcount = 0; Es wird verwendet, um zu beobachten, ob die ArrayList gleichzeitig von anderen Threads geändert wird. Wenn es inkonsistent ist, wird eine synchrone Ausnahme ausgelöst. *ThemodCountValuethattheiterBelievestheBacking *ListshouldHave. Wenn diese Erwartung isvioliert ist, hat der THEERTERATOR *HASDETECTECTECTECED CONCURRENTMODIFICATION. */intExwardModcount = modcount; // Wenn der Cursor nicht die Größe der Liste erreicht, gibt es immer noch Elemente. publicBoolean hasNext () {returnCursor! = size (); } // Geben Sie das aktuelle Element zurück und dann Cursor +1. Neuer Index = Index der zurückgegebenen Elemente. public e next () {checkforComodification (); Versuchen Sie {e next = get (cursor); Lastret = Cursor ++; Als nächstes zurückkehren; } catch (indexoutOfBoundSexception e) {checkforComodification (); geworfene NoSuchelementException (); }}/*Ein Element löschen, was bedeutet, das aktuelle Element zu löschen und Cursor-1 zu setzen. Denn die Liste verschiebt alle folgenden Elemente in die vorherige. */ publicVoid remove () {if (lastret == -1) geworfen illegalStateException (); checkforComodification (); try {AbstractList.this.Remove (Lastret); if (lastret <cursor) cursor--; Lastret = -1; erweitertModcount = modcount; } catch (indexoutOfboundSexception e) {geworfene ConcurrentModificationException (); }} FinalVoid checkForComodification () {if (modcount! = erwartungsModcount) geworfene ConcurrentModificationException (); }}Zusammenfassen
Wie Sie sehen können, löscht Iterator das Element und setzt den Cursor auf den richtigen Sitz zurück. Solange keine anderen Threads gleichzeitig den Satz ändern, wird es kein Problem geben. Das obige dreht sich alles um diesen Artikel. Ich hoffe, es wird für alle hilfreich sein, Java zu lernen.