159

我有一个List<SomeBean>从 Web 服务填充的。我想将该列表的内容复制/克隆到相同类型的空列表中。用于复制列表的 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后来在代码中得到了一个。打击和审判。:)

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

4

14 回答 14

268

只需使用这个:

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

注意:仍然不是线程安全的,如果您otherList从另一个线程进行修改,那么您可能想要制作otherList(甚至newList) a CopyOnWriteArrayList,例如 - 或使用锁定原语,例如ReentrantReadWriteLock来序列化对任何列表的读/写访问并发访问。

于 2013-01-14T13:53:44.687 回答
37

这是一种非常好的 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());
于 2015-12-10T12:36:50.617 回答
23
originalArrayList.addAll(copyArrayofList);

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

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

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

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;
}
于 2016-04-04T10:26:31.823 回答
7

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

我有一个 ConcurrentAccessException

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

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

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

  • 找一个地方避免需要复制原始列表。

于 2013-01-14T13:58:36.667 回答
6

Java 10开始:

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

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

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

此外,如果您想创建 a 的深层副本,您可以在此处List找到许多好的答案。

于 2018-04-15T17:24:40.267 回答
5

Java 8 还有另一种方法是空安全的。

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())
于 2017-12-14T12:32:40.307 回答
1

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

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

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

List<SomeBean> wsListCopy=new ArrayList<SomeBean>(wsList);  
于 2013-01-14T19:54:45.740 回答
1

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

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

for (CartItem item : prodList) {
  tempList.add(item);
}
prodList.clear();
prodList = new ArrayList<>(tempList);

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

于 2015-10-16T04:24:51.107 回答
1

您可以使用 addAll()。

例如:wsListCopy.addAll(wsList);

于 2018-01-03T04:30:56.383 回答
0

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

于 2013-10-10T17:51:23.823 回答
0

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

于 2018-04-27T11:47:43.413 回答
0

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

List<String> myList = new ArrayList<>();
myList.add("a");
myList.add("b");
List<String> copyList = new ArrayList<>();
copyList.addAll(myList);
于 2020-12-04T19:45:42.597 回答
0

以防万一您使用龙目岛:

使用以下注释标记 SomeBean:

@Builder(toBuilder = true, builderMethodName = "")

Lombok 将使用复制构造函数为您执行对象的浅拷贝:

inputList.stream()
         .map(x -> x.toBuilder().build())
         .collect(Collectors.toList());
于 2022-01-07T23:51:13.660 回答
-3

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

于 2015-06-04T14:20:36.243 回答