文档章节

Java 8 的 groupingBy 产生空的 Map 分组

孟飞阳
 孟飞阳
发布于 2017/04/02 21:30
字数 486
阅读 176
收藏 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.getGender)));

//输出:{male=[Tom, Jerry]}

Stream<Person> stream = Stream.of(new Person("Tom", "female"), new Person("Jerry", "male"));
System.out.println(stream.collect(Collectors.groupingBy(person -> person.getGender)));
//输出:{female=[tom], male=[Jerry]}

而无法表示存在其他 gender 的可能性,并且 female=[] 的情况,即想要结果

{male=[Tom, Jerry], female=[]}

如果想得到以上的结果该当如何呢? stream.collect() 接受一个 Collector, Collectors 中只是定义了许多常用的 Collector 实现,如果不够用的话我们可以实现自己的 Collector. 下面就来定义一个 GroupingWithKeys, 它需要实现 java.util.stream.Collector 接口,有五个接口方法. 事成之后我们写

Stream<Person> stream = Stream.of(new Person("Tom", "male"), new Person("Jerry", "male"));
System.out.println(stream.collect(new GroupingWithKeys<>(person -> person.gender, "male", "female")));

能够得到输出:

{male=[Tom, Jerry], female=[]}

下面是 Person 和 GroupingWithKeys 两个类的完整代码

GroupingWithKeys.java

class GroupingWithKeys<T, K> implements Collector<T, Map<K, List<T>>, Map<K, List<T>>> {

  private List<K> possibleKeys = Collections.emptyList();
  private Function<T, K> keyGenerator;

  public GroupingWithKeys(Function<T, K> keyGenerator, K...possibleKeys) {  //构造时传入 Key 生成器和可能的 Keys
    if(possibleKeys != null) {
      this.possibleKeys = Arrays.asList(possibleKeys);
    }
    this.keyGenerator = keyGenerator;
  }

  @Override
  public Supplier<Map<K, List<T>>> supplier() {
    return () -> {
      Map<K, List<T>> map = new LinkedHashMap<>();
      possibleKeys.forEach(s -> map.put(s, new ArrayList<T>())); //按 possibleKeys 依次用空列表填充 Map
      return map;
    };
  }

  @Override
  public BiConsumer<Map<K, List<T>>, T> accumulator() {
    return (map, t) -> {
      List<T> list = map.getOrDefault(keyGenerator.apply(t), new ArrayList<T>());
      list.add(t);
      map.put(keyGenerator.apply(t), list);
    };
  }

  @Override
  public BinaryOperator<Map<K, List<T>>> combiner() {
    return (map1, map2) -> {
      map1.putAll(map2);
      return map1;
    };
  }

  @Override
  public Function<Map<K, List<T>>, Map<K, List<T>>> finisher() {
    return Function.identity();
  }

  @Override
  public Set<Characteristics> characteristics() {
    return Collections.unmodifiableSet(EnumSet.of(IDENTITY_FINISH, CONCURRENT));
  }
}

在上面的 supplier() 方法中为所有可能的 Keys 准备好一个空的 List, 然后填充好 Map .

Person.java

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;
  }
}

Java 既然提供了 java.util.stream.Collector 接口让我们扩展,那么想要什么样的 Collector 就自己创建吧。

© 著作权归作者所有

孟飞阳
粉丝 217
博文 1056
码字总数 566359
作品 5
朝阳
个人站长
私信 提问
归约与分组 - 读《Java 8实战》

区分Collection,Collector和collect 代码中用到的类与方法用红框标出,可从git库中查看 收集器用作高级归约 预定义收集器的功能 将流元素归约和汇总为一个值 元素分组 元素分区,分组的特殊情...

yysue
2018/08/16
65
0
Java 8中Stream相关用法实践

Java 8中Stream相关用法实践(https://github.com/hollischuang/toBeTopJavaer/blob/master/basics/java-basic/stream.md) 参考示例发下: 1. jcode-java-8-streams-collectors-flatmapping(h......

近在咫尺远在天涯
07/03
61
0
死磕Java 8特性系列---流的深入

本次,读了两本书,一本是《Beginning Java 8 Language Features》,一本是《Java 8 实战》,有感。感觉平时我们都是使用了个Java8相关特性的皮毛。加上以前面试被人问:你知道一个列表我想同...

心中的理想乡
2018/09/19
92
1
将一个list分成多个list

将一个list或其他集合按需分成多份,例如,分批发送等,是很常见的需求,但是Java传统的集合操作似乎没有提供这一支持。 幸好,google guava 和apache commons collections都提供了相应的实现...

春哥大魔王的博客
03/11
379
0
Java8里请不要再使用循环语句

正如我之前所写的,Java 8中的新功能特性改变了游戏规则。对Java开发者来说这是一个全新的世界,并且是时候去适应它了。 在这篇文章里,我们将会去了解传统循环的一些替代方案。在Java 8的新...

程序师
2018/06/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

golang-字符串-地址分析

demo package mainimport "fmt"func main() {str := "map.baidu.com"fmt.Println(&str, str)str = str[0:5]fmt.Println(&str, str)str = "abc"fmt.Println(&s......

李琼涛
今天
4
0
Spring Boot WebFlux 增删改查完整实战 demo

03:WebFlux Web CRUD 实践 前言 上一篇基于功能性端点去创建一个简单服务,实现了 Hello 。这一篇用 Spring Boot WebFlux 的注解控制层技术创建一个 CRUD WebFlux 应用,让开发更方便。这里...

泥瓦匠BYSocket
今天
6
0
从0开始学FreeRTOS-(列表与列表项)-3

FreeRTOS列表&列表项的源码解读 第一次看列表与列表项的时候,感觉很像是链表,虽然我自己的链表也不太会,但是就是感觉很像。 在FreeRTOS中,列表与列表项使用得非常多,是FreeRTOS的一个数...

杰杰1号
今天
8
0
Java反射

Java 反射 反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的 Class,Class 类 用于表示.class 文件(字节码)) 一、反射的概述 定义:JAVA 反射机制是在运行状态中,对于任...

zzz1122334
今天
5
0
聊聊nacos的LocalConfigInfoProcessor

序 本文主要研究一下nacos的LocalConfigInfoProcessor LocalConfigInfoProcessor nacos-1.1.3/client/src/main/java/com/alibaba/nacos/client/config/impl/LocalConfigInfoProcessor.java p......

go4it
昨天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部