92

Is there a way to copy a TreeSet? That is, is it possible to go

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

tempList = itemList;

or do you have to physically iterate through the sets and copy them one by one?

syntagma
  • 23,346
  • 16
  • 78
  • 134
SNpn
  • 2,157
  • 8
  • 36
  • 53

5 Answers5

167

Another way to do this is to use the copy constructor:

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>(oldSet);

Or create an empty set and add the elements:

Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>();
newSet.addAll(oldSet);

Unlike clone these allow you to use a different set class, a different comparator, or even populate from some other (non-set) collection type.


Note that the result of copying a Set is a new Set containing references to the objects that are elements if the original Set. The element objects themselves are not copied or cloned. This conforms with the way that the Java Collection APIs are designed to work: they don't copy the element objects.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
9

Starting from Java 10:

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

Set.copyOf() returns an unmodifiable Set containing the elements of the given Collection.

The given Collection must not be null, and it must not contain any null elements.

Oleksandr Pyrohov
  • 14,685
  • 6
  • 61
  • 90
7

With Java 8 you can use stream and collect to copy the items:

Set<Item> newSet = oldSet.stream().collect(Collectors.toSet());

Or you can collect to an ImmutableSet (if you know that the set should not change):

Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());
Yosi Dahari
  • 6,794
  • 5
  • 24
  • 44
  • 9
    You can ... but the copy constructor (etc) should be more efficient if you are simply copying a collection. – Stephen C Jan 09 '18 at 05:47
4

Java 8+:

Set<String> copy = new HashSet<>(mySet); 
J. Doe
  • 12,159
  • 9
  • 60
  • 114
3

The copy constructor given by @Stephen C is the way to go when you have a Set you created (or when you know where it comes from). When it comes from a Map.entrySet(), it will depend on the Map implementation you're using:

findbugs says

The entrySet() method is allowed to return a view of the underlying Map in which a single Entry object is reused and returned during the iteration. As of Java 1.6, both IdentityHashMap and EnumMap did so. When iterating through such a Map, the Entry value is only valid until you advance to the next iteration. If, for example, you try to pass such an entrySet to an addAll method, things will go badly wrong.

As addAll() is called by the copy constructor, you might find yourself with a Set of only one Entry: the last one.

Not all Map implementations do that though, so if you know your implementation is safe in that regard, the copy constructor definitely is the way to go. Otherwise, you'd have to create new Entry objects yourself:

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));

Edit: Unlike tests I performed on Java 7 and Java 6u45 (thanks to Stephen C), the findbugs comment does not seem appropriate anymore. It might have been the case on earlier versions of Java 6 (before u45) but I don't have any to test.

Matthieu
  • 2,736
  • 4
  • 57
  • 87
  • 1
    Is this based on observation? If so, that sounds like a bug in the `addAll` implementation. FWIW, the `Map` implementations I have looked all iterate the entry set (at some level), and *extract the key and value for each one*. The fact that the entry set iterator might return the same object each doesn't time doesn't matter. The only case I saw that was different was `EnumMap` where the copy constructor itself was cloning the entries ... if the source map was an `EnumMap`. – Stephen C Sep 18 '15 at 23:15
  • 1
    @StephenC it seems you're right: the tests I've done with `IdentityHashMap` do not lead to that bug. More troubling is that I tested it on Java 6u45 and there was no problem either. I guess this is a bug in findbugs (or the JDK they based their rules on...). I'll edit my answer. – Matthieu Sep 20 '15 at 08:20