Copy a List to Another List in Java – 在Java中复制一个列表到另一个列表

最后修改: 2018年 7月 18日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this quick tutorial, we’ll explore different ways to copy a List to another List, and a common error produced in the process.

在这个快速教程中,我们将探讨将一个List复制到另一个List>的不同方法,以及在此过程中产生的一个常见错误。

For an introduction to the use of Collections, please refer to this article here.

关于Collections的使用介绍,请参考这里的文章

2. Constructor

2.建筑商

A simple way to copy a List is by using the constructor that takes a collection as its argument:

复制List的一个简单方法是使用以集合为参数的构造函数。

List<Plant> copy = new ArrayList<>(list);

Since we’re copying references here, and not cloning the objects, every amends made in one element will affect both lists.

因为我们在这里复制引用,而不是克隆对象,所以在一个元素中的每一个修改都会影响到两个列表。

As such, it’s good to use the constructor for copying immutable objects:

因此,使用构造函数来复制不可变的对象是很好的。

List<Integer> copy = new ArrayList<>(list);

Integer is an immutable class; its value is set when the instance is created, and can never change.

Integer是一个不可变的类;它的值在实例被创建时被设置,并且永远不会改变。

An Integer reference can thus be shared by multiple lists and threads, and there’s no way anybody can change its value.

因此,一个Integer引用可以被多个列表和线程共享,而且任何人都不可能改变它的值。

3. List ConcurrentAccessException

3.List ConcurrentAccessException

A common problem working with lists is the ConcurrentAccessException. This usually means that we’re modifying the list while we’re trying to copy it, most likely in another thread.

处理列表的一个常见问题是ConcurrentAccessException这通常意味着我们在试图复制列表时正在修改它,很可能是在另一个线程中。

To fix this issue, we have to either:

为了解决这个问题,我们必须做到以下两点。

  • Use a collection designed for concurrent access
  • Lock the collection appropriately to iterate over it
  • Find a way to avoid needing to copy the original collection

Considering our last approach, it isn’t thread-safe. If we want to resolve our problem with the first option, we may want to use CopyOnWriteArrayList, in which all mutative operations are implemented by making a fresh copy of the underlying array.

考虑到我们的最后一种方法,它并不是线程安全的。如果我们想用第一种方法解决我们的问题,我们可能想使用CopyOnWriteArrayList,其中所有的变异操作都是通过对底层数组进行新的拷贝来实现的。

For further information, please refer to this article.

关于进一步的信息,请参考这篇文章

If we want to lock the Collection, it’s possible to use a lock primitive to serialized read/write access, such as ReentrantReadWriteLock.

如果我们想锁定Collection,可以使用一个锁基元来序列化读/写访问,比如ReentrantReadWriteLock

4. AddAll

4.添加所有

Another approach to copying elements is using the addAll method:

另一种复制元素的方法是使用 addAll方法。

List<Integer> copy = new ArrayList<>();
copy.addAll(list);

It’s important to keep in mind whenever using this method that, as with the constructor, the contents of both lists will reference the same objects.

在使用这个方法时,必须记住,与构造函数一样,两个列表的内容将引用相同的对象。

5. Collections.copy

5.Collections.copy

The Collections class consists exclusively of static methods that operate on, or return collections.

Collections类完全由操作或返回集合的静态方法组成。

One of them is copy, which needs a source list and a destination list that’s at least as long as the source.

其中之一是copy,它需要一个源列表和一个至少与源一样长的目标列表。

It will maintain the index of each copied element in the destination list, such as the original:

它将维护目标列表中每个被复制的元素的索引,如原始的。

List<Integer> source = Arrays.asList(1,2,3);
List<Integer> dest = Arrays.asList(4,5,6);
Collections.copy(dest, source);

In the above example, all the previous elements in the dest list were overwritten because both lists have the same size.

在上面的例子中, dest 列表中所有先前的元素都被覆盖了,因为两个列表的大小相同。

If the destination list size is larger than the source:

如果目标列表的大小大于源文件。

List<Integer> source = Arrays.asList(1, 2, 3);
List<Integer> dest = Arrays.asList(5, 6, 7, 8, 9, 10);
Collections.copy(dest, source);

Here, just the first three items were overwritten, while the rest of the elements in the list were conserved.

在这里,只有前三个项目被覆盖,而列表中的其他元素被保留下来。

6. Using Java 8

6.使用Java 8

This version of Java expands our possibilities by adding new tools. The one we’ll explore in the following examples is Stream:

这个版本的Java通过增加新的工具扩大了我们的可能性。我们将在下面的例子中探讨的是Stream

List<String> copy = list.stream()
  .collect(Collectors.toList());

The main advantage of this option is the ability to use skip and filters. In the next example, we’ll skip the first element:

这个选项的主要优点是能够使用跳过和过滤器。在下一个例子中,我们将跳过第一个元素。

List<String> copy = list.stream()
  .skip(1)
  .collect(Collectors.toList());

It’s also possible to filter by the length of the String, or by comparing an attribute of our objects:

也可以通过String,的长度或者通过比较我们对象的一个属性来进行过滤。

List<String> copy = list.stream()
  .filter(s -> s.length() > 10)
  .collect(Collectors.toList());
List<Flower> flowers = list.stream()
  .filter(f -> f.getPetals() > 6)
  .collect(Collectors.toList());

It’s probable we want to work in a null-safe way:

这很可能是我们想以一种不安全的方式工作。

List<Flower> flowers = Optional.ofNullable(list)
  .map(List::stream)
  .orElseGet(Stream::empty)
  .collect(Collectors.toList());

We’ll likely want to skip an element in this way too:

我们很可能也想通过这种方式跳过一个元素。

List<Flower> flowers = Optional.ofNullable(list)
  .map(List::stream).orElseGet(Stream::empty)
  .skip(1)
  .collect(Collectors.toList());

7. Using Java 10

7.使用Java 10

Finally, one of the last Java versions allows us to create an immutable List containing the elements of the given Collection:

最后,最近的一个Java版本允许我们创建一个不可变的List,包含给定Collection>的元素:

List<T> copy = List.copyOf(list);
The only conditions are that the given Collection mustn’t be null, or contain any null elements.

8. Conclusion

8.结语

In this article, we learned various ways to copy a List to another List with different Java versions. We also examined a common error produced in the process.
As always, code samples can be found over on GitHub, here and here.