Java 将流转换为集合,流处理完成之后,用户希望将流转换为 List
、Set
或其他线性集合。使用 Collectors
工具类定义的 toList
、toSet
或 toCollection
方法。Java 8 一般通过称为流水线(pipeline)的中间操作(intermediate operation)来传递流元素,并在达到终止操作(terminal operation)后结束。
Java 将流转换为集合 问题描述
流处理完成之后,用户希望将流转换为 List
、Set
或其他线性集合。
Java 将流转换为集合 解决方案
使用 Collectors
工具类定义的 toList
、toSet
或 toCollection
方法。
Java 将流转换为集合 具体实例
Java 8 一般通过称为流水线(pipeline)的中间操作(intermediate operation)来传递流元素,并在达到终止操作(terminal operation)后结束。Stream
接口定义的 collect
方法就是一种终止操作,用于将流转换为集合。
collect
方法有两种重载形式,如例 4-7 所示。
例 4-7
Stream.collect
方法
本范例采用第一种形式,它传入 Collector
作为参数。收集器执行“可变归约操作”(mutable reduction operation),将元素累加至结果容器(result container),此时结果是一个集合。
由于 java.util.stream.Collector
属于接口,无法被实例化。Collector
接口包含一个称为 of
的静态方法,它用于生成 Collector
,但通常有更好(或至少更简单)的方式可以实现这一点。
Java 8 API 经常使用静态方法
of
作为工厂方法。
Collectors
类定义的静态方法将用于生成 Collector
实例,它作为 Stream.collect
方法的参数来填充集合。
例 4-82 显示了一个创建 List
的简单示例。
2本范例中出现的人名来自《神秘兵团》,这是 20 世纪 90 年代最为人所忽视的电影之一。(Furious 说:“Lance Hunt 就是神奇队长。”Shoveler 答道:“Lance Hunt 戴眼镜,但神奇队长不戴。”Furious 说:“他变身时会把眼镜摘下来。”Shoveler 答道:“怎么可能!他根本看不见!”)
例 4-8 创建
List
上述方法创建了一个 ArrayList
类,并采用给定的流元素进行填充。创建 Set
也很简单,如例 4-9 所示。
例 4-9 创建
Set
➊ 重复的人名(将在转换为 Set
时删除)
上述方法创建了一个 HashSet
类的实例并加以填充,并忽略任何重复的人名。
例 4-8 和例 4-9 均使用默认的数据结构:对于 List
是 ArrayList
,对于 Set
是 HashSet
。如果希望指定某种特定的数据结构,则应使用 Collectors.toCollection
方法,它传入 Supplier
作为参数。示例代码如例 4-10 所示。
例 4-10 创建关联列表(linked list)
由于 toCollection
方法的参数是集合 Supplier
,本例提供 LinkedList
类的构造函数引用。collect
方法将 LinkedList
实例化,并采用给定的姓名加以填充。
Stream
接口还定义了一个用于创建对象数组的方法 toArray
,它有两种重载形式:
第一种形式返回一个包含流元素的数组,但未指定类型。第二种形式传入一个函数并生成所需类型的新数组,数组的长度与流相同,很容易与数组构造函数引用(array constructor reference)一起使用,如例 4-11 所示。
例 4-11 创建
Array
➊ 数组构造函数引用作为 Supplier
返回数组具有指定的类型,其长度与流中的元素数量匹配。
为了将流转换为 Map
,Collectors.toMap
方法需要传入两个 Function
实例,分别用于键和值。
我们以一个包装 name
和 role
的 Actor
POJO 为例进行讨论。假设一部给定电影中存在 Actor
实例的 Set
,例 4-12 根据这些实例创建了一个 Map
。
例 4-12 创建
Map
➊ 生成键和值所用的函数
输出如下:
利用 Collectors.toConcurrentMap
方法对本例稍作修改,就能创建 ConcurrentMap
。