Angenommen, ich habe eine Reihe von Ganzzahlen und möchte jede Ganzzahl in der Menge erhöhen. Wie würde ich das machen?
Darf ich während des Iterierens Elemente zum Set hinzufügen und daraus entfernen?
Müsste ich einen neuen Satz erstellen, in den ich die Elemente "kopieren und ändern" würde, während ich den ursprünglichen Satz iteriere?
EDIT: Was ist, wenn die Elemente des Sets unveränderlich sind?
cannot
eher alscan
? Wie in,You cannot safely remove
anstattYou can safely remove
? Scheint ein Widerspruch in diesem ersten Absatz zu sein.error: incompatible types: Object cannot be converted to Integer
Sie können tun, was Sie wollen, wenn Sie ein Iteratorobjekt verwenden, um die Elemente in Ihrem Satz zu durchlaufen. Sie können sie unterwegs entfernen und es ist in Ordnung. Wenn Sie sie jedoch in einer for-Schleife entfernen (entweder "Standard" für jede Art), werden Sie in Schwierigkeiten geraten:
Set<Integer> set = new TreeSet<Integer>(); set.add(1); set.add(2); set.add(3); //good way: Iterator<Integer> iterator = set.iterator(); while(iterator.hasNext()) { Integer setElement = iterator.next(); if(setElement==2) { iterator.remove(); } } //bad way: for(Integer setElement:set) { if(setElement==2) { //might work or might throw exception, Java calls it indefined behaviour: set.remove(setElement); } }
Nach dem Kommentar von @ mrgloom gibt es hier weitere Details, warum der oben beschriebene "schlechte" Weg ist, na ja ... schlecht:
Ohne auf zu viele Details darüber einzugehen, wie Java dies implementiert, können wir auf hoher Ebene sagen, dass der "schlechte" Weg schlecht ist, weil er in den Java-Dokumenten eindeutig als solcher festgelegt ist:
https://docs.oracle.com/javase/8/docs/api/java/util/ConcurrentModificationException.html
unter anderem festlegen, dass (Hervorhebung von mir):
Um näher auf Details einzugehen: Ein Objekt, das in einer forEach-Schleife verwendet werden kann, muss die Schnittstelle "java.lang.Iterable" ( hier javadoc ) implementieren . Dies erzeugt einen Iterator (über die in dieser Schnittstelle gefundene "Iterator" -Methode), der bei Bedarf instanziiert wird und intern einen Verweis auf das Iterable-Objekt enthält, aus dem er erstellt wurde. Wenn jedoch ein iterierbares Objekt in einer forEach-Schleife verwendet wird, ist die Instanz dieses Iterators für den Benutzer ausgeblendet (Sie können in keiner Weise selbst darauf zugreifen).
Dies, zusammen mit der Tatsache, dass ein Iterator ziemlich zustandsbehaftet ist, dh um seine Magie zu entfalten und kohärente Antworten für seine "next" - und "hasNext" -Methoden zu erhalten, muss das Hintergrundobjekt nicht durch etwas anderes als den Iterator selbst geändert werden Während der Iteration wird eine Ausnahme ausgelöst, sobald festgestellt wird, dass sich etwas im Hintergrundobjekt geändert hat, während es darüber iteriert.
Java nennt diese "Fail-Fast" -Iteration: dh es gibt einige Aktionen, normalerweise solche, die eine Iterable-Instanz ändern (während ein Iterator darüber iteriert). Der Teil "Fehler" des Begriffs "Fehler schnell" bezieht sich auf die Fähigkeit eines Iterators, zu erkennen, wann solche "Fehler" -Aktionen auftreten. Der "schnelle" Teil des "Fail-Fast" (und meiner Meinung nach "Best-Effort-Fast") beendet die Iteration über ConcurrentModificationException , sobald festgestellt werden kann, dass eine "Fail" -Aktion vorliegt geschehen.
quelle
Ich mag die Semantik des Iterators nicht sehr, bitte betrachten Sie dies als Option. Es ist auch sicherer, wenn Sie weniger von Ihrem internen Status veröffentlichen
private Map<String, String> JSONtoMAP(String jsonString) { JSONObject json = new JSONObject(jsonString); Map<String, String> outMap = new HashMap<String, String>(); for (String curKey : (Set<String>) json.keySet()) { outMap.put(curKey, json.getString(curKey)); } return outMap; }
quelle
Sie können einen veränderlichen Wrapper des primitiven int erstellen und eine Menge davon erstellen:
class MutableInteger { private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } } class Test { public static void main(String[] args) { Set<MutableInteger> mySet = new HashSet<MutableInteger>(); // populate the set // .... for (MutableInteger integer: mySet) { integer.setValue(integer.getValue() + 1); } } }
Wenn Sie ein HashSet verwenden, sollten Sie natürlich die Methode hash, equals in Ihrer MutableInteger implementieren, aber das liegt außerhalb des Rahmens dieser Antwort.
quelle
Erstens glaube ich, dass der Versuch, mehrere Dinge gleichzeitig zu tun, im Allgemeinen eine schlechte Praxis ist, und ich schlage vor, dass Sie darüber nachdenken, was Sie erreichen möchten.
Es ist jedoch eine gute theoretische Frage, und soweit ich weiß , erfüllt die
CopyOnWriteArraySet
Implementierung derjava.util.Set
Schnittstelle Ihre besonderen Anforderungen.http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/CopyOnWriteArraySet.html
quelle