311. Java Stream API - 使用收集器作为终端操作
在 Java 中,Stream API 提供了强大的方式来处理集合数据,其中 collect() 方法是一种常用的终端操作。该方法允许我们将流中的元素收集到不同类型的集合中,如 List、Set 或者自定义的集合类型。collect() 方法的参数是一个 Collector 对象,它定义了如何将流中的元素累积到目标集合。
✅ 使用 Collector 收集流元素
collect() 方法是 Stream 接口中的一个终端方法,接收一个 Collector 对象作为参数。Collector 接口定义了一个API,用于收集数据并将其存储到内存结构中。你可以通过收集器将数据收集到任何实现了 Collection 接口的类中,或者收集到 Map 中,甚至是创建字符串或者其他类型的集合。
Java 提供了许多常用的收集器,这些收集器可以通过 Collectors 工厂类来创建。常见的收集器包括:
-
Collectors.toList():将流元素收集到List中。 -
Collectors.toSet():将流元素收集到Set中。 -
Collectors.toMap():将流元素收集到Map中。
如果这些内置的收集器不能满足需求,你还可以通过实现 Collector 接口来创建自定义收集器。
收集器的不同类型
-
收集到
Collection中:你可以使用Collectors.toList()或Collectors.toSet()将流中的元素收集到List或Set中。 -
自定义收集器:如果你需要收集元素到一个不同的集合类型,可以使用
toCollection(supplier)方法。通过这个方法,你可以指定使用特定的Supplier来创建集合。
收集器的限制
-
专门化流:
IntStream、LongStream和DoubleStream是数值流,它们只支持一个收集器,即不接受Collector类型的参数。因此,无法直接在这些流上使用Collectors.toList()或Collectors.toSet()。
示例:使用收集器收集流中的元素
示例 1:收集到 List 中
List<Integer> numbers =
IntStream.range(0, 10)
.boxed()
.collect(Collectors.toList());
System.out.println("numbers = " + numbers);
此代码段首先使用 IntStream.range(0, 10) 生成一个从 0 到 9 的整数流。boxed() 方法将 IntStream 转换为 Stream<Integer>,然后通过 collect(Collectors.toList()) 将这些元素收集到一个 List 中。
输出:
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
示例 2:收集到 Set 中(去重)
Set<Integer> evenNumbers =
IntStream.range(0, 10)
.map(number -> number / 2)
.boxed()
.collect(Collectors.toSet());
System.out.println("evenNumbers = " + evenNumbers);
此代码段先通过 IntStream.range(0, 10) 生成一个从 0 到 9 的整数流。然后,使用 map() 方法将每个数字除以 2,接着将流转换为 Stream<Integer>。最后,通过 collect(Collectors.toSet()) 将结果收集到 Set 中,自动去除重复值。
输出:
evenNumbers = [0, 1, 2, 3, 4]
示例 3:使用 Supplier 创建 LinkedList 并收集元素
LinkedList<Integer> linkedList =
IntStream.range(0, 10)
.boxed()
.collect(Collectors.toCollection(LinkedList::new));
System.out.println("linked list = " + linkedList);
在这个示例中,使用 toCollection() 方法和 LinkedList::new 提供的 Supplier 来创建 LinkedList 实例,最终将 Stream<Integer> 中的元素收集到 LinkedList 中。
输出:
linked list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
✅ 不可变集合
有时候,你可能需要收集流中的元素到一个不可变的集合中。Collectors 工厂类提供了 toUnmodifiableList() 和 toUnmodifiableSet() 两个方法,分别用于创建不可变的 List 和 Set。
示例:收集到不可变集合
List<Integer> immutableList =
IntStream.range(0, 5)
.boxed()
.collect(Collectors.toUnmodifiableList());
System.out.println("immutableList = " + immutableList);
输出:
immutableList = [0, 1, 2, 3, 4]
这个 immutableList 是不可变的,因此不能再向其中添加、删除或修改元素。
✅ 自定义收集器
如果你有特别的需求,无法满足于 Collectors 类提供的常用收集器,你可以实现自己的 Collector 接口。例如,假设你希望根据某些特定规则将流中的元素分组或累积到自定义的结构中。通过实现 Collector 接口,你可以完全控制元素的收集过程。
小结:
-
常用收集器:
Collectors.toList()、Collectors.toSet()、Collectors.toMap()等,适用于将流元素收集到常见的集合类型中。 -
自定义收集器:通过实现
Collector接口,你可以创建自己的收集器,收集元素到自定义的集合中。 -
不可变集合:
toUnmodifiableList()和toUnmodifiableSet()让你可以轻松地创建不可变集合。 -
专门化流:
IntStream、LongStream和DoubleStream不能使用接受Collector参数的collect()方法,只支持一个特殊的收集操作。
收集器是 Java Stream API 中非常强大的功能,通过掌握它的使用,你可以灵活地将流中的元素累积到各种集合中,并且能够根据需求进行扩展和定制。