在Java中把一个列表复制到另一个列表
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);