我们在 Java 8 之前用 for-loop 对 List 进行分组的时候,可能会要求产生空的分组。例如对 List<Person> 按性能进行分组,即使给定的 List<Person> 中全是 male, 我们也想得到 Map 包含两个 Key
{male=[person1, person2], female=[]}
而不只是
{male=[person1, person2]}
这两种表示略有区别,第一种方式暗示着有另一种可能性。看看 for-loop 如何对 List<Person> 进行分组。
类 Person 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
class Person { public final String name; public final String gender; public Person(String name, String gender) { this.name = name; this.gender = gender; } @Override public String toString() { return name; } } |
进行分组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
List<Person> list = Arrays.asList(new Person("Tom", "male"), new Person("Jerry", "male")); Map<String, List<Person>> grouped = new HashMap<>(); List<Person> maleGroup = new ArrayList<>(); List<Person> femaleGroup = new ArrayList<>(); for(Person person: list) { if(person.gender.equals("male")) { maleGroup.add(person); } else { femaleGroup.add(person); } } grouped.put("male", maleGroup); grouped.put("female", femaleGroup); System.out.println(grouped); |
得到结果是
{female=[], male=[Tom, Jerry]}
如果我们换成 Java 8 的 groupingBy 的写法
1 2 3 |
List<Person> list = Arrays.asList(new Person("Tom", "male"), new Person("Jerry", "male")); Map<String, List<Person>> grouped = list.stream().collect(groupingBy(person -> person.gender)); System.out.println(grouped); |
结果中的组只能是列表元素中存在的 gender 属性值
{male=[Tom, Jerry]}
当然上面从 list 到 groupingBy 时根本不存在 female 的信息,那么能否告知 groupingBy 对不存在 gender 生成空列表呢? 好像无法做到
1 2 |
Map<String, List<Person>> grouped = list.stream() .collect(groupingBy(person -> "male".equals(person.gender) ? "male" : "female")); |
怎么才能向 groupingBy 传递要为列表 ["male", "female"] 中的所有元素创建一个分组呢? 即便是某个分组是空的,找不到匹配的元素。
慢着,当我读到 Partitioning 部分时,眼前又亮了一下. Partitioning 是给 Stream 分两组,非此即比,如代码
1 2 3 4 |
List<Person> list = Arrays.asList(new Person("Tom", "male"), new Person("Jerry", "male")); Map<Boolean, List<Person>> grouped = list.stream() .collect(partitioningBy(t -> "male".equals(t.name))); System.out.println(grouped); |
输出为
{false=[Tom, Jerry], true=[]}
注意到了吗,true 是一个空的列表,说明 partitioning 有能力生成空的列表,进一步猜想 groupingBy 如能稍加打造是否也能做到像 {female=[], make=[Tom, Jerry]} 这样的输出呢?
partitioningBy 一启动便预置了两个 key, true 和 false, 对于 grouping 的话恐怕是必须要创建自己的 groupingBy 方法,它能够接受一个列表来预定义 Map 中所有的 key.