Java 分区与分组,用户希望将元素集合分为若干个类别,Collectors.partitioningBy
方法将元素拆分为满足 Predicate
与不满足 Predicate
的两类。Collectors.groupingBy
方法生成一个由类别构成的 Map
,其中值为每个类别中的元素。
Java 分区与分组 问题描述
用户希望将元素集合分为若干个类别。
Java 分区与分组 解决方案
Collectors.partitioningBy
方法将元素拆分为满足 Predicate
与不满足 Predicate
的两类。Collectors.groupingBy
方法生成一个由类别构成的 Map
,其中值为每个类别中的元素。
Java 分区与分组 具体实例
假设存在一个由字符串构成的集合,可以通过 partitioningBy
方法将这些字符串按偶数长度和奇数长度进行划分,如例 4-20 所示。
例 4-20 根据偶数或奇数长度对字符串分区
List<String> strings = Arrays.asList("this", "is", "a", "long", "list", "of",
"strings", "to", "use", "as", "a", "demo");
Map<Boolean, List<String>> lengthMap = strings.stream()
.collect(Collectors.partitioningBy(s -> s.length() % 2 == 0)); ➊
lengthMap.forEach((key,value) -> System.out.printf("%5s: %s%n", key, value));
//
// false: [a, strings, use, a]
// true: [this, is, long, list, of, to, as, demo]
➊ 根据偶数或奇数长度进行分区
partitioningBy
方法包括两种形式:
static <T> Collector<T,?,Map<Boolean,List<T>>> partitioningBy(
Predicate<? super T> predicate)
static <T,D,A> Collector<T,?,Map<Boolean,D>> partitioningBy(
Predicate<? super T> predicate, Collector<? super T,A,D> downstream)
可以看到,返回类型中涉及泛型(generics),因此略显复杂,不过实际开发中很少会用到它们。两种 partitioningBy
方法的结果成为 collect
方法的参数,该方法使用生成的收集器来创建由第三个泛型参数定义的输出映射。
第一种 partitioningBy
方法传入单个 Predicate
作为参数,它将元素分为满足 Predicate
与不满足 Predicate
的两类。我们总是可以得到一个恰好包含两个条目的 Map
,其中一个值列表满足 Predicate
,另一个则不满足 Predicate
。
partitioningBy
方法的重载形式传入 Collector
作为第二个参数,它称为下游收集器。它支持对分区返回的列表进行后期处理,相关讨论请参见范例下游收集器。
而 groupingBy
方法执行的操作类似于 SQL 的 GROUP BY
语句。该方法返回一个 Map
,其中键为分组,值为各个分组中的元素列表。
如果从数据库获取数据,请务必将分组操作放在数据库中执行,因为 Java 8 新增的方法适合处理内存中的数据。
groupingBy
方法的签名如下:
static <T,K> Collector<T,?,Map<K,List<T>>> groupingBy(
Function<? super T,? extends K> classifier)
Function
参数传入流的各个元素,并提取需要分组的元素。接下来,我们不是将字符串简单地分为两类,而是根据长度进行划分,如例 4-21 所示。
例 4-21 根据长度对字符串分组
List<String> strings = Arrays.asList("this", "is", "a", "long", "list", "of",
"strings", "to", "use", "as", "a", "demo");
Map<Integer, List<String>> lengthMap = strings.stream()
.collect(Collectors.groupingBy(String::length)); ➊
lengthMap.forEach((k,v) -> System.out.printf("%d: %s%n", k, v));
//
// 1: [a, a]
// 2: [is, of, to, as]
// 3: [use]
// 4: [this, long, list, demo]
// 7: [strings]
➊ 根据长度进行分组
对于所生成的映射,键为字符串长度(1、2、3、4、7),值为各个长度的字符串列表。