在Java中将一个List复制到另一个List

2023/06/07

1. 概述

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

有关集合的使用介绍,请参阅此处的这篇文章

2. 构造函数

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

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

由于我们在这里复制引用,而不是克隆对象,因此对一个元素所做的每一次修改都会影响两个列表

因此,最好使用构造函数来复制不可变对象:

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

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

因此,一个Integer引用可以被多个列表和线程共享,并且任何人都无法更改它的值。

3. List ConcurrentAccessException

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

要解决此问题,我们必须:

  • 使用专为并发访问而设计的集合
  • 适当地锁定集合以迭代它
  • 找到一种避免需要复制原始集合的方法

考虑到我们最后的方法,它不是线程安全的。如果我们想用第一个选项解决我们的问题,我们可能需要使用CopyOnWriteArrayList,其中所有可变操作都是通过制作底层数组的新副本来实现的。

要了解更多信息,请参阅这篇文章

如果我们想锁定Collection,可以使用锁定原语来序列化读/写访问,例如ReentrantReadWriteLock。

4. AddAll

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

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

无论何时使用此方法,请务必记住,与构造函数一样,两个列表的内容将引用相同的对象

5. Collections.copy

Collections类专门包含对集合进行操作或返回集合的静态方法。

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

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

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

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

如果目标列表大小大于源列表:

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

在这里,只有前三个元素被覆盖,而列表中的其余元素被保留。

6. 使用Java 8

这个版本的Java通过添加新工具扩展了我们的可能性。我们将在以下示例中探讨的是Stream:

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

此选项的主要优点是能够使用skip和filter。在下一个示例中,我们将跳过第一个元素:

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

也可以通过字符串的长度进行过滤,或者通过比较对象的属性来进行过滤:

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());

我们可能希望以空安全的方式工作:

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

我们也可能希望以这种方式跳过一个元素:

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

7. 使用Java 10

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

List<T> copy = List.copyOf(list);

唯一的条件是给定的Collection不能为null,或包含任何null元素。

8. 总结

在本文中,我们学习了在不同Java版本中将一个List复制到另一个List的各种方法。我们还检查了该过程中产生的一个常见错误。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章