Java 获取元素数量,用户希望获取流中元素的数量。使用 java.util.stream.Stream
接口定义的 count
方法,或 java.util.stream.Collectors
类定义的 counting
方法。本范例相当简单,目的是为范例下游收集器讨论的下游收集器作铺垫。
Java 获取元素数量 问题描述
用户希望获取流中元素的数量。
Java 获取元素数量 解决方案
使用 java.util.stream.Stream
接口定义的 count
方法,或 java.util.stream.Collectors
类定义的 counting
方法。
Java 获取元素数量 具体实例
本范例相当简单,目的是为范例下游收集器讨论的下游收集器作铺垫。
如例 3-39 所示,Stream
接口定义了 count
默认方法,它能返回 long
型数据。
例 3-39 利用
Stream.count
方法获取元素数量
long count = Stream.of(3, 1, 4, 1, 5, 9, 2, 6, 5).count();
System.out.printf("There are %d elements in the stream%n", count); ➊
➊ 打印 There are 9 elements in the stream
count
方法的有趣之处在于它的实现方式。根据 Javadoc 的描述,“这是一种特殊的归约操作,相当于”:
return mapToLong(e -> 1L).sum();
首先,流的每个元素都被映射为 1(long
)。然后,mapToLong
方法生成 LongStream
,它定义了 sum
方法。换言之,先将所有元素映射为 1,再将它们相加,简单明了。
此外,Collectors
类定义了一种类似的方法 counting
,如例 3-40 所示。
例 3-40 利用
Collectors.counting
方法获取元素数量
count = Stream.of(3, 1, 4, 1, 5, 9, 2, 6, 5)
.collect(Collectors.counting());
System.out.printf("There are %d elements in the stream%n", count);
这两种方法得到的结果并无不同,但既然已有 Stream.count
,为什么还要讨论 Collectors.counting
呢?
我们当然可以使用 Stream.count
方法,按说也应该这样处理。不过“下游收集器”(downstream collector)的使用将在范例下游收集器进行详细讨论。就目前而言,我们考虑例 3-41。
例 3-41 对根据长度划分的字符串计数
Map<Boolean, Long> numberLengthMap = strings.stream()
.collect(Collectors.partitioningBy(
s -> s.length() % 2 == 0, ➊
Collectors.counting())); ➋
numberLengthMap.forEach((k,v) -> System.out.printf("%5s: %d%n", k, v));
//
// false: 4
// true: 8
❶ 谓词
❷ 下游收集器
partitioningBy
方法的第一个参数是 Predicate
,其作用是将字符串分为满足谓词和不满足谓词的两类。如果 partitioningBy
方法只有这一个参数,则结果为 Map<Boolean, List<String>>
,其中键为 true
和 false
,值为偶数长度和奇数长度字符串的列表。
本例采用 partitioningBy
方法的双参数重载形式,它传入 Predicate
和 Collector
。Collector
被称为下游收集器,用于对返回的每个字符串列表进行后期处理。这就是 Collectors.counting
方法的用例。双参数形式的 partitioningBy
方法将输出 Map<Boolean, Long>
,其值为流中偶数长度和奇数长度字符串的数量。
Stream
接口定义的其他几种方法在 Collectors
类中也有对应的方法,其他章节将对它们进行讨论。简而言之,直接处理流时请使用 Stream
定义的方法,而 Collectors
定义的方法适用于 partitioningBy
或 groupingBy
操作的下游后期处理。