Antworten:
Eine andere Möglichkeit, dies zu tun, ist die Verwendung des Kopierkonstruktors :
Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>(oldSet);
Oder erstellen Sie eine leere Menge und fügen Sie die Elemente hinzu:
Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>();
newSet.addAll(oldSet);
Im Gegensatz zu clone
diesen können Sie eine andere Set-Klasse, einen anderen Komparator oder sogar einen anderen (nicht set) Auflistungstyp verwenden.
Beachten Sie, dass das Ergebnis des Kopierens von a neu Set
istSet
das Verweise auf die Objekte enthält, die Elemente des Originals sind Set
. Die Elementobjekte selbst werden nicht kopiert oder geklont. Dies entspricht der Funktionsweise der Java- Collection
APIs: Sie kopieren die Elementobjekte nicht.
Mit Java 8 können Sie die Elemente verwenden stream
und collect
kopieren:
Set<Item> newSet = oldSet.stream().collect(Collectors.toSet());
Oder Sie können zu einem sammeln ImmutableSet
(wenn Sie wissen, dass sich das Set nicht ändern sollte):
Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());
Der von @Stephen C bereitgestellte Kopierkonstruktor ist der richtige Weg, wenn Sie einen Set
erstellt haben (oder wenn Sie wissen, woher er kommt). Wenn es von a kommt Map.entrySet()
, hängt es von der Map
Implementierung ab, die Sie verwenden:
findbugs sagt
Die entrySet () -Methode kann eine Ansicht der zugrunde liegenden Map zurückgeben, in der ein einzelnes Entry-Objekt während der Iteration wiederverwendet und zurückgegeben wird. Ab Java 1.6 haben dies sowohl IdentityHashMap als auch EnumMap getan. Wenn Sie eine solche Karte durchlaufen, ist der Eintragswert nur gültig, bis Sie zur nächsten Iteration übergehen. Wenn Sie beispielsweise versuchen, ein solches entrySet an eine addAll-Methode zu übergeben, wird ein schwerwiegender Fehler auftreten.
Wie addAll()
vom Kopierkonstruktor aufgerufen, befindet sich möglicherweise nur ein Eintrag: der letzte.
Dies Map
tun jedoch nicht alle Implementierungen. Wenn Sie also wissen, dass Ihre Implementierung in dieser Hinsicht sicher ist, ist der Kopierkonstruktor definitiv der richtige Weg. Andernfalls müssten Sie selbst neue Entry
Objekte erstellen :
Set<K,V> copy = new HashSet<K,V>(map.size());
for (Entry<K,V> e : map.entrySet())
copy.add(new java.util.AbstractMap.SimpleEntry<K,V>(e));
Bearbeiten: Im Gegensatz zu Tests, die ich mit Java 7 und Java 6u45 durchgeführt habe (dank Stephen C), scheint der Findbugs-Kommentar nicht mehr angemessen zu sein. Möglicherweise war dies bei früheren Versionen von Java 6 (vor u45) der Fall, aber ich muss keine testen.
addAll
Implementierung. FWIW, die Map
Implementierungen , die ich mir angesehen habe, durchlaufen alle den Eintragssatz (auf einer bestimmten Ebene) und extrahieren den Schlüssel und den Wert für jeden einzelnen . Die Tatsache, dass der Iterator des Eintragssatzes möglicherweise jedes Mal dasselbe Objekt zurückgibt, spielt keine Rolle. Der einzige Fall, den ich anders sah, war, dass EnumMap
der Kopierkonstruktor selbst die Einträge klonte ... wenn die Quellkarte eine war EnumMap
.
IdentityHashMap
führen nicht zu diesem Fehler. Beunruhigender ist, dass ich es auf Java 6u45 getestet habe und es auch kein Problem gab. Ich denke, dies ist ein Fehler in Findbugs (oder dem JDK, auf dem ihre Regeln basieren ...). Ich werde meine Antwort bearbeiten.
Ab Java 10 :
Set<E> oldSet = Set.of();
Set<E> newSet = Set.copyOf(oldSet);
Set.copyOf()
Gibt eine nicht modifizierbare Datei zurück, Set
die die Elemente der angegebenen enthält Collection
.
Das Gegebene Collection
darf nicht sein null
und darf keine null
Elemente enthalten .
tempList.addAll(itemList)