关于Java使用groupingBy分组数据乱序问题
时间:2022-07-23
本文章向大家介绍关于Java使用groupingBy分组数据乱序问题,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
这是对最近做的一个项目,其中一个知识点的总结。
真实的业务场景就不说了,我来模拟下业务场景,足够说明问题就行了。
假设我有个对象,存储人员的基本信息,如下:
@AllArgsConstructor
@Data
@ToString
public class PersonInfo {
private String name;
private int age;
private int sex; //0表示男性,1表示女性
}
添加一些测试数据,
List<PersonInfo> personInfoList = new ArrayList<>();
personInfoList.add(new PersonInfo("tom", 32, 1));
personInfoList.add(new PersonInfo("jerry", 30, 1));
personInfoList.add(new PersonInfo("alice", 15, 0));
personInfoList.add(new PersonInfo("jack", 23, 1));
personInfoList.add(new PersonInfo("aya", 32, 0));
打印下看看,
personInfoList.forEach(e -> System.out.println(e));
PersonInfo(name=tom, age=32, sex=1)
PersonInfo(name=jerry, age=30, sex=1)
PersonInfo(name=alice, age=15, sex=0)
PersonInfo(name=jack, age=23, sex=1)
PersonInfo(name=aya, age=32, sex=0)
我们可以看到,打印的顺序和我们添加的顺序是一样的。
现在我们有个需求,按照性别进行分组。
这个也不难,在 java8 环境下我们可以使用stream流的groupingBy
很容易的实现,于是就有了下面的代码,
Map<Integer, List<PersonInfo>> map = personInfoList.stream().collect(Collectors.groupingBy(PersonInfo::getSex));
groupingBy
实现类似SQL语句的“Group By”字句功能,实现根据一些属性进行分组并把结果存在Map实例。
打印结果看看是怎样的,
map.forEach((key, value) -> System.out.println(key + ": " + value));
0: [PersonInfo(name=alice, age=15, sex=0), PersonInfo(name=aya, age=32, sex=0)]
1: [PersonInfo(name=tom, age=32, sex=1), PersonInfo(name=jerry, age=30, sex=1), PersonInfo(name=jack, age=23, sex=1)]
结果确实是按照要求分组了,但是PersonInfo对象的顺序和我们之前添加的顺序不一样了,在有些业务场景下,这种结果往往是不允许的。(比如分页查询等)
为什么顺序会乱的?
我们先来看看这个map是哪个类型的,
System.out.println(map.getClass().getSimpleName());
打印出来的结果是 HashMap
。
这个就解释了为啥顺序被打乱了, HashMap
在存储是数据时,是先用key做hash计算,然后根据hash的结果决定这条数据的位置,因为hash本身是无序的,导致了读出的顺序是乱的。
知道了原因后,那就很容易想到解决方案了, groupingBy
有一个重载的方法,允许我们指定map进行操作,
Collector<T, ?, M> groupingBy(Function<? super T, ? extends K> classifier,
Supplier<M> mapFactory,
Collector<? super T, A, D> downstream)
注意看第二个参数, Supplier
是java8提供的一中函数接口类型,用于提供一个对象, 根据尖括号里的定义,这里需要提供一个Map
类型的对象。
另外我们知道HashMap
和LinkedHashMap
的区别是后者通过双向链表保证数据插入的顺序和访问的顺序一致。 于是就有了下面的代码,
Map<Integer, List<PersonInfo>> map = personInfoList.stream().collect(Collectors.groupingBy(PersonInfo::getSex, LinkedHashMap::new, Collectors.toList()));
打印的结果是,
1: [PersonInfo(name=tom, age=32, sex=1), PersonInfo(name=jerry, age=30, sex=1), PersonInfo(name=jack, age=23, sex=1)]
0: [PersonInfo(name=alice, age=15, sex=0), PersonInfo(name=aya, age=32, sex=0)]
可以看到打印的顺序和原来的list顺序是一样的。
- ASP.NET TreeView相关问题
- 温故而知新:WinForm/Silverlight多线程编程中如何更新UI控件的值
- ASP.Net Web Page深入探讨
- 用Design+Blend轻松制作环形文字
- 对asp.net响应事件的试验
- 为服务器控件加入客户端事件处理的几种方法
- 温故而知新:Delegate,Action,Func,匿名方法,匿名委托,事件
- 如何在Silverlight4中使用摄像头
- Flask的集中控制
- 64位IIS(IIS6/IIS7)上跑Asp + Jet.Oledb的设置要点
- windows 2003 32位系统能支持的最大内存数
- .Net Core内存回收模式及性能测试对比
- silverlight中顺序/倒序异步加载多张图片
- MySQL数据库性能优化之三
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- php实现银联商务公众号+服务窗支付的示例代码
- php使用json-schema模块实现json校验示例
- 17个品牌,113款5G手机,5G离我们越来越近。
- PHP的cookie与session原理及用法详解
- Thinkphp5.0框架视图view的循环标签用法示例
- Thinkphp5.0 框架视图view的比较标签用法分析
- laravel 操作数据库常用函数的返回值方法
- laravel 验证错误信息到 blade模板的方法
- thinkPHP+LayUI 流加载实现功能
- Thinkphp5.0框架使用模型Model的获取器、修改器、软删除数据操作示例
- laravel5.2表单验证,并显示错误信息的实例
- ThinkPHP 5.1 跨域配置方法
- PHP调用接口API封装的例子
- php-fpm超时时间设置request_terminate_timeout资源问题分析
- laravel框架添加数据,显示数据,返回成功值的方法