在Java中把一个列表复制到另一个列表

评论 0 浏览 0 2018-07-19

1.概述

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

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

2.构造器

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

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

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

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

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

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

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

3. 列出 ConcurrentAccessException

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

要解决这个问题,我们必须要做的是:

  • 使用一个为并发访问而设计的集合
  • 适当地锁定集合,以便对其进行迭代
  • 找到一种方法来避免需要复制原始的集合

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

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

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

4.全部添加

另一种复制元素的方法是使用 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());

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

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

也可以通过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());

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

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版本允许我们创建一个不可变的List,其中包含给定的Collection:中的元素。

List<T> copy = List.copyOf(list);
唯一的条件是给定的 Collection 不能为 null,或包含任何 null 元素。

8.结语

在本文中,我们学习了将一个 List 复制到另一个具有不同 Java 版本的 List 的各种方法。 我们还检查了过程中产生的一个常见错误。
与往常一样,可以在 GitHub 上的 此处此处找到代码示例。
最后更新2023-03-11
0 个评论
标签