Java 将流转换为集合

Java 将流转换为集合,流处理完成之后,用户希望将流转换为 ListSet 或其他线性集合。使用 Collectors 工具类定义的 toListtoSettoCollection 方法。Java 8 一般通过称为流水线(pipeline)的中间操作(intermediate operation)来传递流元素,并在达到终止操作(terminal operation)后结束。

Java 将流转换为集合 问题描述

流处理完成之后,用户希望将流转换为 ListSet 或其他线性集合。

Java 将流转换为集合 解决方案

使用 Collectors 工具类定义的 toListtoSettoCollection 方法。

Java 将流转换为集合 具体实例

Java 8 一般通过称为流水线(pipeline)的中间操作(intermediate operation)来传递流元素,并在达到终止操作(terminal operation)后结束。Stream 接口定义的 collect 方法就是一种终止操作,用于将流转换为集合。
collect 方法有两种重载形式,如例 4-7 所示。

例 4-7 Stream.collect 方法

<R,A> R collect(Collector<? super T,A,R> collector)
<R>   R collect(Supplier<R> supplier,
                BiConsumer<R,? super T> accumulator,
                BiConsumer<R,R> combiner)

本范例采用第一种形式,它传入 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

List<String> superHeroes =
    Stream.of("Mr. Furious", "The Blue Raja", "The Shoveler",
              "The Bowler", "Invisible Boy", "The Spleen", "The Sphinx")
          .collect(Collectors.toList());

上述方法创建了一个 ArrayList 类,并采用给定的流元素进行填充。创建 Set 也很简单,如例 4-9 所示。

例 4-9 创建 Set

Set<String> villains =
    Stream.of("Casanova Frankenstein", "The Disco Boys",
              "The Not-So-Goodie Mob", "The Suits", "The Suzies",
              "The Furriers", "The Furriers")  ➊
          .collect(Collectors.toSet());
}

➊ 重复的人名(将在转换为 Set 时删除)
上述方法创建了一个 HashSet 类的实例并加以填充,并忽略任何重复的人名。
例 4-8 和例 4-9 均使用默认的数据结构:对于 ListArrayList,对于 SetHashSet。如果希望指定某种特定的数据结构,则应使用 Collectors.toCollection 方法,它传入 Supplier 作为参数。示例代码如例 4-10 所示。

例 4-10 创建关联列表(linked list)

List<String> actors =
    Stream.of("Hank Azaria", "Janeane Garofalo", "William H. Macy",
              "Paul Reubens", "Ben Stiller", "Kel Mitchell", "Wes Studi")
          .collect(Collectors.toCollection(LinkedList::new));
}

由于 toCollection 方法的参数是集合 Supplier,本例提供 LinkedList 类的构造函数引用。collect 方法将 LinkedList 实例化,并采用给定的姓名加以填充。
Stream 接口还定义了一个用于创建对象数组的方法 toArray,它有两种重载形式:

Object[] toArray();
<A> A[]      toArray(IntFunction<A[]> generator);

第一种形式返回一个包含流元素的数组,但未指定类型。第二种形式传入一个函数并生成所需类型的新数组,数组的长度与流相同,很容易与数组构造函数引用(array constructor reference)一起使用,如例 4-11 所示。

例 4-11 创建 Array

String[] wannabes =
    Stream.of("The Waffler", "Reverse Psychologist", "PMS Avenger")
          .toArray(String[]::new); ➊
}

➊ 数组构造函数引用作为 Supplier
返回数组具有指定的类型,其长度与流中的元素数量匹配。
为了将流转换为 MapCollectors.toMap 方法需要传入两个 Function 实例,分别用于键和值。
我们以一个包装 nameroleActor POJO 为例进行讨论。假设一部给定电影中存在 Actor 实例的 Set,例 4-12 根据这些实例创建了一个 Map

例 4-12 创建 Map

Set<Actor> actors = mysteryMen.getActors();

Map<String, String> actorMap = actors.stream()
    .collect(Collectors.toMap(Actor::getName, Actor::getRole));  ➊

actorMap.forEach((key,value) ->
    System.out.printf("%s played %s%n", key, value));

➊ 生成键和值所用的函数
输出如下:

Janeane Garofalo played The Bowler
Greg Kinnear played Captain Amazing
William H. Macy played The Shoveler
Paul Reubens played The Spleen
Wes Studi played The Sphinx
Kel Mitchell played Invisible Boy
Geoffrey Rush played Casanova Frankenstein
Ben Stiller played Mr. Furious
Hank Azaria played The Blue Raja

利用 Collectors.toConcurrentMap 方法对本例稍作修改,就能创建 ConcurrentMap

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程