如何将 java.util.List 复制到另一个 java.util.List

Posted

技术标签:

【中文标题】如何将 java.util.List 复制到另一个 java.util.List【英文标题】:How to copy a java.util.List into another java.util.List 【发布时间】:2012-12-28 11:44:01 【问题描述】:

我有一个从 Web 服务填充的 List<SomeBean>。我想将该列表的内容复制/克隆到相同类型的空列表中。用于复制列表的 Google 搜索建议我使用 Collections.copy() 方法。在我看到的所有示例中,目标列表应该包含要进行复制的确切项目数。

由于我正在使用的列表是通过 Web 服务填充的,并且它包含数百个对象,因此我无法使用上述技术。还是我用错了??!!无论如何,为了让它工作,我尝试做这样的事情,但我仍然得到了一个IndexOutOfBoundsException

List<SomeBean> wsList = app.allInOne(template);

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList.size());   
Collections.copy(wsListCopy,wsList);
System.out.println(wsListCopy.size());

我尝试使用wsListCopy=wsList.subList(0, wsList.size()),但后来在代码中得到了ConcurrentAccessException。打击和审判。 :)

无论如何,我的问题很简单,如何将我的列表的全部内容复制到另一个列表中?当然不是通过迭代。

【问题讨论】:

任何副本当然都会使用迭代。你可以把它藏起来,但它仍然会在那里。 首先:您确定需要复制该列表吗?你这样做的动机是什么? 是的,迭代只是隐藏在这些层之下。但是添加了评论以防止任何迭代答案。 :) @ppeterka 我正在对列表执行操作,例如 removeAll()。这会导致列表丢失其原始数据。之后也需要“那个数据”。 app.allInOne(template) 返回的列表的实际类型是什么? ArrayList? 【参考方案1】:

就用这个吧:

List<SomeBean> newList = new ArrayList<SomeBean>(otherList);

注意:仍然不是线程安全的,如果您从另一个线程修改otherList,那么您可能希望将otherList(甚至newList)设为CopyOnWriteArrayList,例如——或使用锁原语,例如ReentrantReadWriteLock,用于序列化对同时访问的任何列表的读/写访问。

【讨论】:

现在,我只是觉得自己很愚蠢 :) 我希望这样构建它不会抛出任何ConcurrentAccessException Javadoc: docs.oracle.com/javase/1.4.2/docs/api/java/util/… +1 如果他遇到 ConcurrentModifcationException,他有一个并发问题需要先解决。 如果问题提到“复制/克隆”,为什么这个答案会得到这么多分数?这个,只要其他一些答案与克隆无关。无论您使用何种特定于集合/流的实用程序方法,都将为集合内的对象保留相同的引用。 答案是错误的。内容不会被复制。只是它的参考。【参考方案2】:

这是一种非常好的 Java 8 方法:

List<String> list2 = list1.stream().collect(Collectors.toList());

当然,这里的好处是您可以过滤并跳转到仅部分列表的副本。

例如

//don't copy the first element 
List<String> list2 = list1.stream().skip(1).collect(Collectors.toList());

【讨论】:

结果列表是原始列表的深拷贝还是浅拷贝? 浅拷贝。 遗憾的是,这也不是线程安全的。假设在收集器运行时更​​改了list,则会抛出ConcurrentModificationException @Dan,如何跳过复制最后一个元素? @chandresh 跳过复制最后一个元素,您只需使用.limit(list1.size() - 1)【参考方案3】:
originalArrayList.addAll(copyArrayofList);

请记住,无论何时使用 addAll() 方法进行复制,对相同对象的两个数组列表(originalArrayList 和 copyArrayofList)引用的内容都将添加到列表中,所以如果您修改其中任何一个,copyArrayofList 也将反映相同的变化。

如果您不想要副作用,那么您需要将每个元素从 originalArrayList 复制到 copyArrayofList,例如使用 for 或 while 循环。对于深拷贝,您可以使用下面的代码 sn-p。

但您还需要做一件事,实现 Cloneable 接口并覆盖 SomeBean 类的 clone() 方法。

public static List<SomeBean> cloneList(List<SomeBean> originalArrayList) 
    List<SomeBean> copyArrayofList = new ArrayList<SomeBean>(list.size());
    for (SomeBean item : list) copyArrayofList.add(item.clone());
    return clone;

【讨论】:

这是这里为数不多的正确答案之一,因为它指定#addAll 进行浅拷贝,以及如何进行深拷贝。更多详情:***.com/questions/715650/…【参考方案4】:

我试图做这样的事情,但我仍然得到一个 IndexOutOfBoundsException。

我遇到了 ConcurrentAccessException

这意味着您在尝试复制列表时正在修改列表,很可能是在另一个线程中。要解决这个问题,你必须要么

使用为并发访问而设计的集合。

适当地锁定集合,以便您可以对其进行迭代(或允许您调用为您执行此操作的方法)

想办法避免复制原始列表。

【讨论】:

【参考方案5】:

Java 10 开始:

List<E> oldList = List.of();
List<E> newList = List.copyOf(oldList);

List.copyOf() 返回一个不可修改的List,其中包含给定Collection 的元素。

给定的Collection 不能是null,并且不能包含任何null 元素。

另外,如果您想创建List 的深层副本,您可以找到很多好的答案here。

【讨论】:

【参考方案6】:

在 Java 8 中还有另一种方法是 null 安全的。

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
    .map(Collection::stream)
    .orElseGet(Stream::empty)
    .collect(Collectors.toList());

如果你想跳过一个元素。

List<SomeBean> wsListCopy = Optional.ofNullable(wsList)
    .map(Collection::stream)
    .orElseGet(Stream::empty)
    .skip(1)
    .collect(Collectors.toList());

Java 9+可以使用Optional的stream方法

Optional.ofNullable(wsList)
    .stream()
    .flatMap(Collection::stream)
    .collect(Collectors.toList())

【讨论】:

【参考方案7】:

我遇到了同样的问题 ConcurrentAccessException,我的解决方案是:

List<SomeBean> tempList = new ArrayList<>();

for (CartItem item : prodList) 
  tempList.add(item);

prodList.clear();
prodList = new ArrayList<>(tempList);

所以它一次只工作一个操作并且避免了 Exeption...

【讨论】:

【参考方案8】:

我尝试了类似的方法并且能够重现问题(IndexOutOfBoundsException)。以下是我的发现:

1) Collections.copy(destList, sourceList) 的实现首先通过调用 size() 方法检查目标列表的大小。由于对 size() 方法的调用将始终返回列表中的元素数(在本例中为 0),因此构造函数 ArrayList(capacity) 仅确保后备数组的初始容量,这与列表的大小。因此我们总是得到 IndexOutOfBoundsException。

2) 一种相对简单的方法是使用以集合为参数的构造函数:

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  

【讨论】:

【参考方案9】:

你可以使用 addAll()。

例如:wsListCopy.addAll(wsList);

【讨论】:

【参考方案10】:

回复:indexOutOfBoundsException,您的子列表参数是问题;您需要以 size-1 结束子列表。从零开始,列表的最后一个元素总是 size-1,在 size 位置没有元素,因此会出错。

【讨论】:

【参考方案11】:

我看不到任何正确答案。如果你想要一个深拷贝,你必须手动迭代和复制对象(你可以使用复制构造函数)。

【讨论】:

这是这里为数不多的真实答案之一。更多详情:***.com/questions/715650/…【参考方案12】:

您应该使用addAll 方法。它将指定集合中的所有元素附加到副本列表的末尾。这将是您列表的副本。

List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);

【讨论】:

【参考方案13】:

subList 函数是个技巧,返回的对象还在原来的列表中。 所以如果你在subList中做任何操作,无论是单线程还是多线程,都会导致你的代码并发异常。

【讨论】:

以上是关于如何将 java.util.List 复制到另一个 java.util.List的主要内容,如果未能解决你的问题,请参考以下文章

在列表迭代期间从 java.util.List 中删除元素时引发 ConcurrentModificationException? [复制]

java 如何把一个list里的相同数的出现次数输出成另一个list

将字符串数组转换为 java.util.List

java.util.list的基础功能

MFC中,如何将CBitmap中的图片复制到另一CBitmap的一块区域中,即如何读取一个CBit

如何将 XIB 复制到另一个项目?