有没有办法复制一个 TreeSet
?也就是说,是否可以这样做?
Set <Item> itemList;
Set <Item> tempList;
tempList = itemList;
还是必须通过迭代遍历集合并逐个复制它们?
另一种做法是使用复制构造函数:
Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>(oldSet);
或者创建一个空集合并添加元素:
Collection<E> oldSet = ...
TreeSet<E> newSet = new TreeSet<E>();
newSet.addAll(oldSet);
与clone
不同,这些方法允许你使用不同的类集合、不同的比较器,甚至可以从其他(非Set)集合类型中填充。
注意,复制一个Set
的结果是一个新的Set
,其中包含对原始Set
中作为元素的对象的引用。元素对象本身不会被复制或克隆。这符合Java Collection
API的设计方式:它们不会复制元素对象。
Set<E> oldSet = Set.of();
Set<E> newSet = Set.copyOf(oldSet);
Set.copyOf()
方法返回一个不可修改的Set
,其中包含给定Collection
中的元素。
给定的Collection
不能为null
,且不能包含任何null
元素。
使用Java 8,您可以使用stream
和collect
来复制项目:
Set<Item> newSet = oldSet.stream().collect(Collectors.toSet());
或者,如果您知道集合不应更改,可以收集到ImmutableSet
中:
Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());
Java 8+:
Set<String> copy = new HashSet<>(mySet);
Set
(或者您知道它来自哪里)时使用的方法。如果它来自于Map.entrySet()
,那么它将取决于您正在使用的Map
实现:
< p > findbugs说
由于复制构造函数调用了entrySet()方法允许返回基础Map的视图,在此视图中单个Entry对象在迭代期间被重用并返回。截至Java 1.6,IdentityHashMap和EnumMap都这样做。当遍历此类Map时,仅当您进入下一次迭代时,Entry值才有效。例如,如果您尝试将这样的entrySet传递给addAll方法,事情将会出错。
addAll()
,因此您可能会发现自己只有一个Entry的Set:最后一个。
不是所有的 Map
实现都可以这样做,所以如果您知道您的实现在这方面是安全的,复制构造函数绝对是正确的方式。否则,您必须自己创建新的 Entry
对象:
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));
编辑:与我在Java 7和Java 6u45上执行的测试不同(感谢Stephen C),findbugs评论似乎不再适用。这可能是在Java 6的早期版本(u45之前)的情况,但我没有任何测试。
addAll
实现中的一个bug。就我所看到的Map
实现而言,它们都会迭代entry set(在某个级别上)并提取每个条目的键和值。事实上,entry set迭代器可能每次返回相同的对象并不重要。我看到的唯一不同之处是EnumMap
,其中复制构造函数本身正在克隆条目……如果源映射是一个EnumMap
。 - Stephen CIdentityHashMap
进行的测试并没有出现那个 bug。更令人不安的是,我在 Java 6u45 上进行了测试,也没有问题。我猜这是 findbugs 的一个 bug(或者是他们基于的 JDK 的规则有问题...)。我会编辑我的回答。 - Matthieu