Kopieren setzt Java

83

Gibt es eine Möglichkeit, eine zu kopieren TreeSet? Das heißt, ist es möglich zu gehen

Set <Item> itemList;
Set <Item> tempList;

tempList = itemList;

oder müssen Sie die Sets physisch durchlaufen und einzeln kopieren?

SNpn
quelle
7
tempList.addAll(itemList)
Dhblah

Antworten:

155

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 clonediesen 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 SetistSet 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- CollectionAPIs: Sie kopieren die Elementobjekte nicht.

Stephen C.
quelle
7

Mit Java 8 können Sie die Elemente verwenden streamund collectkopieren:

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());
Yosi Dahari
quelle
8
Sie können ... aber der Kopierkonstruktor (usw.) sollte effizienter sein, wenn Sie einfach eine Sammlung kopieren.
Stephen C
3

Der von @Stephen C bereitgestellte Kopierkonstruktor ist der richtige Weg, wenn Sie einen Seterstellt haben (oder wenn Sie wissen, woher er kommt). Wenn es von a kommt Map.entrySet(), hängt es von der MapImplementierung 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 Maptun 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 EntryObjekte 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.

Matthieu
quelle
1
Basiert dies auf Beobachtung? Wenn ja, klingt das wie ein Fehler in der addAllImplementierung. FWIW, die MapImplementierungen , 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 EnumMapder Kopierkonstruktor selbst die Einträge klonte ... wenn die Quellkarte eine war EnumMap.
Stephen C
1
@StephenC Sie scheinen Recht zu haben: Die Tests, mit denen ich gearbeitet habe, IdentityHashMapfü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.
Matthieu
3

Ab Java 10 :

Set<E> oldSet = Set.of();
Set<E> newSet = Set.copyOf(oldSet);

Set.copyOf()Gibt eine nicht modifizierbare Datei zurück, Setdie die Elemente der angegebenen enthält Collection.

Das Gegebene Collectiondarf nicht sein nullund darf keine nullElemente enthalten .

Oleksandr Pyrohov
quelle
2

Java 8+ :

Set<String> copy = new HashSet<>(mySet); 
J. Doe
quelle