Java 8 的 groupingBy 产生空的 Map 分组
前面一篇 Java 8 的 groupingBy 能否产生空的 Map 分组 是提出来的思考,本篇就是上一篇的答案。
由于在 Java 8 中用 Collectors.groupingBy 对 List 进行分组时每个组里都必须存在元素,也就是
能够得到输出
GroupingWithKeys.java
在上面的 supplier() 方法中为所有可能的 Keys 准备好一个空的 List, 然后填充好 Map .
Person.java
Java 既然提供了 java.util.stream.Collector 接口让我们扩展,那么想要什么样的 Collector 就自己创建吧。 永久链接 https://yanbin.blog/java-8-groupingby-empty-map-group/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。
由于在 Java 8 中用 Collectors.groupingBy 对 List 进行分组时每个组里都必须存在元素,也就是
Stream<Person> stream = Stream.of(new Person("Tom", "male"), new Person("Jerry", "male"));只能得到结果
System.out.println(stream.collect(Collectors.groupingBy(person -> person.gender)));
{male=[Tom, Jerry]}而无法表示存在其他 gender 的可能性,并且 female=[] 的情况,即想要结果
{male=[Tom, Jerry], female=[]}如果想得到以上的结果该当如何呢? stream.collect() 接受一个 Collector, Collectors 中只是定义了许多常用的 Collector 实现,如果不够用的话我们可以实现自己的 Collector. 下面就来定义一个 GroupingWithKeys, 它需要实现 java.util.stream.Collector 接口,有五个接口方法. 事成之后我们写
1Stream<Person> stream = Stream.of(new Person("Tom", "male"), new Person("Jerry", "male"));
2System.out.println(stream.collect(new GroupingWithKeys<>(person -> person.gender, "male", "female")));能够得到输出
{male=[Tom, Jerry], female=[]}下面是 Person 和 GroupingWithKeys 两个类的完整代码
GroupingWithKeys.java
1class GroupingWithKeys<T, K> implements Collector<T, Map<K, List<T>>, Map<K, List<T>>> {
2
3 private List<K> possibleKeys = Collections.emptyList();
4 private Function<T, K> keyGenerator;
5
6 public GroupingWithKeys(Function<T, K> keyGenerator, K...possibleKeys) { //构造时传入 Key 生成器和可能的 Keys
7 if(possibleKeys != null) {
8 this.possibleKeys = Arrays.asList(possibleKeys);
9 }
10 this.keyGenerator = keyGenerator;
11 }
12
13 @Override
14 public Supplier<Map<K, List<T>>> supplier() {
15 return () -> {
16 Map<K, List<T>> map = new LinkedHashMap<>();
17 possibleKeys.forEach(s -> map.put(s, new ArrayList<T>())); //按 possibleKeys 依次用空列表填充 Map
18 return map;
19 };
20 }
21
22 @Override
23 public BiConsumer<Map<K, List<T>>, T> accumulator() {
24 return (map, t) -> {
25 List<T> list = map.getOrDefault(keyGenerator.apply(t), new ArrayList<T>());
26 list.add(t);
27 map.put(keyGenerator.apply(t), list);
28 };
29 }
30
31 @Override
32 public BinaryOperator<Map<K, List<T>>> combiner() {
33 return (map1, map2) -> {
34 map1.putAll(map2);
35 return map1;
36 };
37 }
38
39 @Override
40 public Function<Map<K, List<T>>, Map<K, List<T>>> finisher() {
41 return Function.identity();
42 }
43
44 @Override
45 public Set<Characteristics> characteristics() {
46 return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT));
47 }
48}在上面的 supplier() 方法中为所有可能的 Keys 准备好一个空的 List, 然后填充好 Map .
Person.java
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}Java 既然提供了 java.util.stream.Collector 接口让我们扩展,那么想要什么样的 Collector 就自己创建吧。 永久链接 https://yanbin.blog/java-8-groupingby-empty-map-group/, 来自 隔叶黄莺 Yanbin's Blog
[版权声明]
本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。