复制集Java


83

有没有办法复制TreeSet?也就是说,有可能去

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

tempList = itemList;

还是您需要物理遍历这些集合并一一复制?


7
tempList.addAll(itemList)
2011年

Answers:


155

另一种方法是使用复制构造函数

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

或创建一个空集并添加元素:

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

clone这些不同,您可以使用不同的集合类,不同的比较器,甚至可以使用其他(非集合)集合类型填充。


请注意,复制a的结果Set是一个新的,Set包含对作为原始元素的对象的引用Set。元素对象本身不会被复制或克隆。这符合Java CollectionAPI设计的工作方式:它们不复制元素对象。


7

使用Java 8,您可以使用streamcollect复制项目:

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

或者,您可以收集到一个ImmutableSet(如果您知道该集合不应更改):

Set<Item> newSet = oldSet.stream().collect(ImmutableSet.toImmutableSet());

8
您可以...,但是如果您只是复制集合,则复制构造函数(等)应该更高效。
斯蒂芬·C

3

@Stephen C给出的副本构造函数是Set创建后(或知道它来自何处)的处理方式。如果来自Map.entrySet(),则取决于Map您使用的实现:

findbugs

允许entrySet()方法返回基础Map的视图,该基础Map中的单个Entry对象在迭代过程中被重用并返回。从Java 1.6开始,IdentityHashMap和EnumMap都这样做了。遍历此类Map时,Entry值仅在前进到下一个迭代之前才有效。例如,如果您尝试将此类entrySet传递给addAll方法,那么事情将会严重出错。

正如addAll()复制构造函数所调用的那样,您可能会发现自己只有一个条目的集合:最后一个。

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之前)可能是这种情况,但是我没有要测试的东西。


1
这是基于观察吗?如果是这样,那听起来像是实现中的错误addAll。FWIW,Map我看过的所有实现都迭代了入口集(在某种程度上),并提取每个的键和值。条目集迭代器可能不会每次都返回相同的对象这一事实并不重要。我看到的唯一不同是EnumMap复制构造函数本身正在克隆条目...如果源映射是EnumMap
斯蒂芬·C

1
@StephenC看来您是对的:我进行的测试IdentityHashMap不会导致该错误。更麻烦的是,我在Java 6u45上对其进行了测试,也没有问题。我猜这是findbugs中的错误(或他们基于其规则的JDK ...)。我将编辑答案。
Matthieu


2

Java 8+

Set<String> copy = new HashSet<>(mySet); 
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.