1. Overview
1.概述
Converting Java collections from one type to another is a common programming task. In this tutorial, we’ll convert any type of Collection to an ArrayList.
将Java集合从一种类型转换为另一种类型是一项常见的编程任务。在本教程中,我们将把任何类型的Collection转换成ArrayList。
Throughout the tutorial, we’ll assume that we already have a collection of Foo objects. From there, we’ll create an ArrayList using various approaches.
在整个教程中,我们将假设我们已经有一个Foo对象的集合。从那里,我们将使用各种方法创建一个ArrayList。
2. Defining Our Example
2.确定我们的范例
But before continuing, let’s model our input and output.
但在继续之前,让我们为我们的输入和输出建模。
Our source could be any type of collection so we’ll declare it using the Collection interface:
我们的源可以是任何类型的集合,所以我们将使用Collection接口声明它。
Collection<Foo> srcCollection;
We need to produce an ArrayList with the same element type:
我们需要产生一个具有相同元素类型的ArrayList。
ArrayList<Foo> newList;
3. Using the ArrayList Constructor
3.使用ArrayList构造函数
The simplest way to copy a collection to a new collection is using its constructor.
将一个集合复制到一个新的集合的最简单方法是使用其构造函数。
In our previous guide to ArrayList, we learned that the ArrayList constructor can accept a collection parameter:
在我们之前的ArrayList指南中,我们了解到ArrayList构造函数可以接受一个集合参数。
ArrayList<Foo> newList = new ArrayList<>(srcCollection);
- The new ArrayList contains a shallow copy of the Foo elements in the source collection.
- The order is the same as one in the source collection.
The simplicity of the constructor makes it a great option in most scenarios.
构造函数的简单性使得它在大多数情况下是一个很好的选择。。
4. Using the Streams API
4.使用流媒体API
Now, let’s take advantage of the Streams API to create an ArrayList from an existing Collection:
现在,让我们利用Streams API,从现有的集合中创建一个ArrayList:
ArrayList<Foo> newList = srcCollection.stream().collect(toCollection(ArrayList::new));
In this snippet:
在这个片断中。
- We take the stream from the source collection and apply the collect() operator to create a List
- We specify ArrayList::new to get the list type we want
- This code will also produce a shallow copy.
If we were not concerned about the exact List type, we could simplify:
如果我们不关心确切的List类型,我们可以进行简化。
List<Foo> newList = srcCollection.stream().collect(toList());
Note that toCollection() and toList() are statically imported from Collectors. To learn more, please refer to our guide on Java 8’s Collectors.
请注意,toCollection()和toList()是静态地从Collectors导入。要了解更多信息,请参考我们的关于Java 8的collectors的指南。
5. Deep Copy
5.深度复制
Before we mentioned “shallow copies”. By that, we mean that the elements in the new list are exactly the same Foo instances that still exist in the source collection. Therefore, we’ve copied the Foos to the newList by reference.
之前我们提到了 “浅层拷贝”。我们的意思是,新列表中的元素正是源集合中仍然存在的Foo实例。因此,我们通过引用将Foos复制到newList中。
If we modify the contents of a Foo instance in either collection that modification will be reflected in both collections. Hence, if we want to modify the elements in either collection without modifying the other we need to perform a “deep copy.”
如果我们修改一个Foo实例在任何一个集合中的内容,该修改将反映在两个集合中。因此,如果我们想修改任何一个集合中的元素,而不修改另一个集合,我们需要执行一个 “深度拷贝”。
To deep copy a Foo, we create a completely new Foo instance for each element. Consequently, all of the Foo fields need to be copied to the new instances.
要深度复制一个Foo,我们为每个元素创建一个全新的Foo实例。因此,所有的Foo字段都需要被复制到新的实例中。
Let’s define our Foo class so that it knows how to deep copy itself:
让我们定义我们的Foo类,以便它知道如何深度复制自己。
public class Foo {
private int id;
private String name;
private Foo parent;
public Foo(int id, String name, Foo parent) {
this.id = id;
this.name = name;
this.parent = parent;
}
public Foo deepCopy() {
return new Foo(
this.id, this.name, this.parent != null ? this.parent.deepCopy() : null);
}
}
Here we can see the fields id and name are int and String. These data types are copied by value. Hence, we can simply assign both of them.
这里我们可以看到字段id和name是int和String。这些数据类型是按值复制的。因此,我们可以简单地把它们都赋值。
The parent field is another Foo, which is a class. If Foo got mutated, any code that shares that reference would be affected by these changes. We have to deep copy the parent field.
parent字段是另一个Foo,它是一个类。如果Foo发生了变化,任何共享该引用的代码都会受到这些变化的影响。我们必须深度复制parent 字段。
Now we can get back to our ArrayList conversion. We just need the map operator to insert the deep copy into the flow:
现在我们可以回到我们的ArrayList转换。我们只需要map操作符来将深度拷贝插入到流程中。
ArrayList<Foo> newList = srcCollection.stream()
.map(foo -> foo.deepCopy())
.collect(toCollection(ArrayList::new));
We can modify the contents of either collection without affecting the other.
我们可以修改其中一个集合的内容而不影响另一个。
A deep copy can be a lengthy process depending on the number of elements and the depth of the data. Using a parallel stream here may provide a performance boost if needed.
深度拷贝可能是一个漫长的过程,取决于元素的数量和数据的深度。如果需要的话,在这里使用一个平行流可以提供一个性能提升。
6. Controlling the List Order
6.控制列表顺序
By default, our stream will deliver elements to our ArrayList in the same order as they are encountered in the source collection.
默认情况下,我们的流将按照在源集合中遇到的相同顺序向我们的ArrayList传递元素。
If we want to change that order we could apply the sorted() operator to the stream. To sort our Foo objects by name:
如果我们想改变这个顺序,我们可以在流中应用sorted()操作符。为了给我们的Foo对象按名字排序。
ArrayList<Foo> newList = srcCollection.stream()
.sorted(Comparator.comparing(Foo::getName))
.collect(toCollection(ArrayList::new));
We can find further details on stream ordering in this earlier tutorial.
我们可以在这个早期的教程中找到关于流排序的进一步细节。
7. Conclusion
7.结论
The ArrayList constructor is an effective way to get the contents of a Collection into a new ArrayList.
ArrayList构造函数是一种有效的方式,可以将Collection的内容获取到一个新的ArrayList中。
However, if we need to tweak the resulting list, the Streams API provides a powerful way to modify the process.
然而,如果我们需要调整产生的列表,Streams API提供了一个强大的方法来修改这个过程。
The code used in this article can be found in its entirety over on GitHub.
本文所使用的代码可以在GitHub上找到其全部内容。