Java8 stream流分组groupingBy的使用方法代码

 更新时间:2024年01月29日 15:14:45   作者:苏格拉帝  
对于java8的新特性groupingBy方法,相信有很多人都在工作中用过,这篇文章主要给大家介绍了关于Java8 stream流分组groupingBy的使用方法,需要的朋友可以参考下

众所周知,使用stream流可以让我们的代码看上去很简洁,现在我们实战使用一下stream的分组与分区。

准备用到的数据类
public class Student{
        //年级
        private String grade;
        //班级
        private String classNumber;
        //姓名
        private String name;
        //年龄
        private int age;
        //地址
        private String address;
        //数学成绩
        private int mathScores;
        //语文成绩
        private int chainessScores;
    }
添加数据
        Student student1 = new Student("701","张三",16,"北京",78,90);
        Student student2 = new Student("700","李四",17,"北京",78,90);
        Student student3 = new Student("703","王五",16,"上海",78,90);
        Student student4 = new Student("701","赵六",16,"上海",78,90);
        Student student5 = new Student("700","钱七",18,"",78,90);
        Student student6 = new Student("701","老八",17,"",78,90);
//这是一个高二年级的成绩单
        List<Student> students = Stream.of(student1,student2,student3,student4,student5,student6).collect(Collectors.toList());

按照班级分组

Map<String, List<Student>> collect = students.stream().collect(Collectors.groupingBy(Student::getClassNumber));
System.out.println(JSON.toJSONString(collect));
//{"700":[{"age":17,"chainessScores":90,"classNumber":"700","mathScores":78,"name":"李四"},{"age":18,"chainessScores":90,"classNumber":"700","mathScores":78,"name":"钱七"}],
//"701":[{"age":16,"chainessScores":90,"classNumber":"701","mathScores":78,"name":"张三"},{"age":16,"chainessScores":90,"classNumber":"701","mathScores":78,"name":"赵六"},{"age":17,"chainessScores":90,"classNumber":"701","mathScores":78,"name":"老八"}],
//"703":[{"age":16,"chainessScores":90,"classNumber":"703","mathScores":78,"name":"王五"}]}

按照班级分组得到每个班级的同学姓名

Map<String, List<String>> collect = students.stream().collect(Collectors.groupingBy(Student::getClassNumber, Collectors.mapping(Student::getName, Collectors.toList())));
System.out.println(JSON.toJSONString(collect));
//{"700":["李四","钱七"],"701":["张三","赵六","老八"],"703":["王五"]}

统计每个班级人数

Map<String, Long> collect = students.stream().collect(Collectors.groupingBy(Student::getClassNumber, Collectors.counting()));
System.out.println(JSON.toJSONString(collect));
//{"700":2,"701":3,"703":1}        

求每个班级的数学平均成绩

Map<String, Double> collect = students.stream().collect(Collectors.groupingBy(Student::getClassNumber, Collectors.averagingDouble(Student::getMathScores)));
System.out.println(JSON.toJSONString(collect));
//{"700":65.0,"701":61.0,"703":82.0}

按班级分组求每个同学的总成绩

Map<String, Map<String, Integer>> collect = students.stream().collect(Collectors.groupingBy(Student::getClassNumber, Collectors.toMap(Student::getName, student -> student.getMathScores() + student.getChainessScores())));
System.out.println(JSON.toJSONString(collect));
//{"700":{"钱七":150,"李四":160},"701":{"张三":168,"老八":148,"赵六":137},"703":{"王五":172}}

嵌套分组,先按班级分组,再按年龄分组

Map<String, Map<Integer, List<Student>>> collect = students.stream().collect(Collectors.groupingBy(Student::getClassNumber, Collectors.groupingBy(Student::getAge)));

分组后得到一个线程安全的ConcurrentMap

ConcurrentMap<String, List<Student>> collect = students.stream().collect(Collectors.groupingByConcurrent(Student::getClassNumber));

加上排序来一波

根据年龄分组并小到大排序,TreeMap默认为按照key升序

TreeMap<Integer, List<String>> collect = students.stream().collect(Collectors.groupingBy(Student::getAge, TreeMap::new, Collectors.mapping(Student::getName, Collectors.toList())));
System.out.println(JSON.toJSONString(collect));
 //{16:["张三","王五","赵六"],17:["李四","老八"],18:["钱七"]}

根据年龄分组并大到小排序,因为TreeMap默认为按照key升序,所以排完顺序再反转一下就OK了

TreeMap<Integer, List<String>> collect = students.stream().collect(Collectors.groupingBy(Student::getAge, TreeMap::new, Collectors.mapping(Student::getName, Collectors.toList())));
Map<Integer, List<String>> collect2 = collect.descendingMap();
System.out.println(JSON.toJSONString(collect2));
//{18:["钱七"],17:["李四","老八"],16:["张三","王五","赵六"]}

附:高级用法

只是个人感觉比上面的高级一些,可能在大佬看来本质上都一样,只是更复杂了一点点。

1. 改变分组后的key和value

在上面的分组中,key还好,在4和5自定义条件分组中,改变了key。但是value呢?好像都是定死了,普通的分组就是该对象的集合,求和、统计就是一个数字,能不能我自己来规定返回的value类型呢?比如我要按照门派分组,得到每个门派里面每个人的名字,不需要其他的性别、年龄信息

代码

// 按照门派分组,分组后 key 为Group对象, value变成String名字
Map<Group, List<String>> collect2 = users.stream()
                .collect(Collectors.groupingBy(x -> new Group(x.getGroup(), x.getGroup() + "的描述"),
                        Collectors.mapping(User::getUsername, Collectors.toCollection(ArrayList::new))));

结果

{BlogMain1.Group(name=明教, desc=明教的描述)=[张无忌, 金毛狮王--谢逊, 紫衫龙王--黛绮丝, 白眉鹰王--殷天正, 青翼蝠王--韦一笑], BlogMain1.Group(name=武当, desc=武当的描述)=[张三丰, 宋远桥, 张翠山, 殷梨亭], BlogMain1.Group(name=少林, desc=少林的描述)=[圆真, 空智], BlogMain1.Group(name=峨眉, desc=峨眉的描述)=[灭绝师太, 周芷若, 宋青书]}

2. 多级分组

先按照一个条件分组,在分组的基础上再按照另一个条件分组

代码

// 多级分组,先按照门派分组,门派里面再按照名字长度分组
Map<Group, Map<Integer, List<User>>> collect3 = users.stream().collect(
        Collectors.groupingBy(x -> new Group(x.getGroup(), x.getGroup() + "的描述"),
                Collectors.groupingBy(x -> x.username.length())));

结果

{BlogMain1.Group(name=明教, desc=明教的描述)={3=[BlogMain1.User(username=张无忌, gender=男, group=明教, age=23)], 8=[BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47)], 9=[BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32), BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38), BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)]}, BlogMain1.Group(name=武当, desc=武当的描述)={3=[BlogMain1.User(username=张三丰, gender=男, group=武当, age=56), BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42), BlogMain1.User(username=张翠山, gender=男, group=武当, age=41), BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37)]}, BlogMain1.Group(name=少林, desc=少林的描述)={2=[BlogMain1.User(username=圆真, gender=男, group=少林, age=35), BlogMain1.User(username=空智, gender=男, group=少林, age=47)]}, BlogMain1.Group(name=峨眉, desc=峨眉的描述)={3=[BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21), BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)], 4=[BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51)]}}

3. 分组排序

就是先分组, 再每组分别排序, 经常写SQL的小伙伴可能经常碰到这个问题, steam api 就非常简单

代码

Map<String, List<User>> userMap = users.stream().collect(Collectors.groupingBy(User::getGender,
        Collectors.mapping(u -> u, Collectors.collectingAndThen(Collectors.toList(),
                sortedStudents -> sortedStudents.stream().sorted((Comparator.comparing(User::getAge)))
                        .collect(Collectors.toList())))));

userMap.forEach((k, v) -> {
    System.err.println("k: " + k);
    v.forEach(System.err::println);
});

结果

k: 女
BlogMain1.User(username=周芷若, gender=女, group=峨眉, age=21)
BlogMain1.User(username=紫衫龙王--黛绮丝, gender=女, group=明教, age=32)
BlogMain1.User(username=灭绝师太, gender=女, group=峨眉, age=51)
k: 男
BlogMain1.User(username=宋青书, gender=男, group=峨眉, age=22)
BlogMain1.User(username=张无忌, gender=男, group=明教, age=23)
BlogMain1.User(username=青翼蝠王--韦一笑, gender=男, group=明教, age=35)
BlogMain1.User(username=圆真, gender=男, group=少林, age=35)
BlogMain1.User(username=殷梨亭, gender=男, group=武当, age=37)
BlogMain1.User(username=白眉鹰王--殷天正, gender=男, group=明教, age=38)
BlogMain1.User(username=张翠山, gender=男, group=武当, age=41)
BlogMain1.User(username=宋远桥, gender=男, group=武当, age=42)
BlogMain1.User(username=金毛狮王--谢逊, gender=男, group=明教, age=47)
BlogMain1.User(username=空智, gender=男, group=少林, age=47)
BlogMain1.User(username=张三丰, gender=男, group=武当, age=56)

4. 我在项目中的使用例子

总结 

到此这篇关于Java8 stream流分组groupingBy使用的文章就介绍到这了,更多相关Java8 stream流分组groupingBy内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis自定义TypeHandler解决特殊类型转换问题详解

    Mybatis自定义TypeHandler解决特殊类型转换问题详解

    这篇文章主要介绍了Mybatis自定义TypeHandler解决特殊类型转换问题详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • java基于NIO实现群聊模式

    java基于NIO实现群聊模式

    这篇文章主要为大家详细介绍了java实现NIO实现群聊模式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • Java PriorityQueue数据结构接口原理及用法

    Java PriorityQueue数据结构接口原理及用法

    这篇文章主要介绍了Java PriorityQueue数据结构接口原理及用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • 浅谈Java安全之C3P0链利用与分析

    浅谈Java安全之C3P0链利用与分析

    本文主要介绍了浅谈Java安全之C3P0链利用与分析,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Java使用Jdbc连接Oracle执行简单查询操作示例

    Java使用Jdbc连接Oracle执行简单查询操作示例

    这篇文章主要介绍了Java使用Jdbc连接Oracle执行简单查询操作,结合实例形式详细分析了java基于jdbc实现Oracle数据库的连接与查询相关操作技巧,需要的朋友可以参考下
    2019-09-09
  • spring配置文件中util:properties和context:property-placeholder用法

    spring配置文件中util:properties和context:property-placeholder用法

    这篇文章主要介绍了spring配置文件中util:properties和context:property-placeholder用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • Java数组的初始化方法详解

    Java数组的初始化方法详解

    在Java程序开发中,数组是一个非常常用的数据类型,数组的初始化是使用数组来存储和处理数据的关键步骤之一,但是,关于Java数组的初始化,经常会让人感到迷惑,本文将详细介绍Java数组的初始化方法,帮助读者从此告别关于Java数组初始化的困惑
    2023-11-11
  • SpringBoot jwt的token如何刷新

    SpringBoot jwt的token如何刷新

    这篇文章主要给大家介绍了关于SpringBoot jwt的token如何刷新的相关资料,Json web token(JWT)是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准,需要的朋友可以参考下
    2023-07-07
  • maven的pom文件与打包详解

    maven的pom文件与打包详解

    pom文件定于了一个maven项目的maven配置,一般pom文件的放在项目或者模块的根目录下。本文详细的介绍了pom文件配置,感兴趣的可以了解一下
    2021-08-08
  • 解决springboot 实体类String转Date类型的坑

    解决springboot 实体类String转Date类型的坑

    这篇文章主要介绍了解决springboot 实体类String转Date类型的坑,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10

最新评论