这是对最近作的一个项目,其中一个知识点的总结。java
真实的业务场景就不说了,我来模拟下业务场景,足够说明问题就好了。函数
假设我有个对象,存储人员的基本信息,以下:测试
@AllArgsConstructor @Data @ToString public class PersonInfo { private String name; private int age; private int sex; //0表示男性,1表示女性 }
添加一些测试数据,code
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)
咱们能够看到,打印的顺序和咱们添加的顺序是同样的。接口
如今咱们有个需求,按照性别进行分组。get
这个也不难,在 java8 环境下咱们可使用stream流的groupingBy
很容易的实现,因而就有了下面的代码,hash
Map<Integer, List<PersonInfo>> map = personInfoList.stream().collect(Collectors.groupingBy(PersonInfo::getSex));
groupingBy
实现相似SQL语句的“Group By”字句功能,实现根据一些属性进行分组并把结果存在Map实例。io
打印结果看看是怎样的,java8
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顺序是同样的。