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),值为各个长度的字符串列表。
极客教程