Java 8 的 groupingBy 能否产生空的 Map 分组

我们在 Java 8 之前用 for-loop 对 List 进行分组的时候,可能会要求产生空的分组。例如对 List<Person> 按性能进行分组,即使给定的 List<Person> 中全是 male, 我们也想得到 Map 包含两个 Key

{male=[person1, person2], female=[]}
而不只是
{male=[person1, person2]}
这两种表示略有区别,第一种方式暗示着有另一种可能性。看看 for-loop 如何对 List<Person> 进行分组。

类 Person 代码
 1class Person {
 2
 3  public final String name;
 4  public final String gender;
 5
 6  public Person(String name, String gender) {
 7    this.name = name;
 8    this.gender = gender;
 9  }
10
11  @Override
12  public String toString() {
13    return name;
14  }
15}

进行分组
 1List<Person> list = Arrays.asList(new Person("Tom", "male"), new Person("Jerry", "male"));
 2Map<String, List<Person>> grouped = new HashMap<>();
 3List<Person> maleGroup = new ArrayList<>();
 4List<Person> femaleGroup = new ArrayList<>();
 5for(Person person: list) {
 6  if(person.gender.equals("male")) {
 7    maleGroup.add(person);
 8  } else {
 9    femaleGroup.add(person);
10  }
11}
12grouped.put("male", maleGroup);
13grouped.put("female", femaleGroup);
14System.out.println(grouped);

得到结果是
{female=[], male=[Tom, Jerry]}
如果我们换成 Java 8 的 groupingBy 的写法
1List<Person> list = Arrays.asList(new Person("Tom", "male"), new Person("Jerry", "male"));
2Map<String, List<Person>> grouped = list.stream().collect(groupingBy(person -> person.gender));
3System.out.println(grouped);

结果中的组只能是列表元素中存在的 gender 属性值
{male=[Tom, Jerry]}
当然上面从 list 到  groupingBy 时根本不存在 female 的信息,那么能否告知 groupingBy 对不存在 gender 生成空列表呢? 好像无法做到
1Map<String, List<Person>> grouped = list.stream()
2      .collect(groupingBy(person -> "male".equals(person.gender) ? "male" : "female"));

怎么才能向 groupingBy 传递要为列表 ["male", "female"] 中的所有元素创建一个分组呢? 即便是某个分组是空的,找不到匹配的元素。

慢着,当我读到 Partitioning 部分时,眼前又亮了一下. Partitioning 是给 Stream 分两组,非此即比,如代码
1List<Person> list = Arrays.asList(new Person("Tom", "male"), new Person("Jerry", "male"));
2Map<Boolean, List<Person>> grouped = list.stream()
3  .collect(partitioningBy(t -> "male".equals(t.name)));
4System.out.println(grouped);

输出为
{false=[Tom, Jerry], true=[]}
注意到了吗,true 是一个空的列表,说明 partitioning 有能力生成空的列表,进一步猜想 groupingBy 如能稍加打造是否也能做到像 {female=[], make=[Tom, Jerry]} 这样的输出呢?

partitioningBy 一启动便预置了两个 key, true 和 false, 对于 grouping 的话恐怕是必须要创建自己的 groupingBy 方法,它能够接受一个列表来预定义 Map 中所有的 key. 永久链接 https://yanbin.blog/java-8-groupingby-howto-generate-empty-map/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。