文章目录
前言
项目中经常在对list集合转map时,输出后的集合是乱序的,但有时候我们希望输出的集合是按照原先list的顺序进行输出,本章内容主要讲解为何list转map后输出乱序,以及如何按顺序输出。
1.Collectors.toMap() 输出乱序
1.1 场景示例
对学生集合根据姓名字段去重,按照原先顺序显示列表,但输出后发现list集合顺序乱了
List<Student> list = new ArrayList<>();
list = list.stream()
.collect(Collectors.toMap(Student::getName, Function.identity(),(oldValue,newValue)->newValue))
.values().stream().collect(Collectors.toList());
查看Collectors.toMap()源码发现其输出的Map是HashMap,而HashMap不是按顺序存的。
1.2 Collectors.toMap()
Collectors.toMap()有三个参数,以Collectors.toMap(Student::getName, Function.identity(), (oldValue, newValue) -> newValue)
为例,第一个参数Student::getName
为Map的key,第二个参数Function.identity()
为value,第三个参数(oldValue, newValue) -> newValue
表示出现相同的key时,取新key值对应的value值。
点进Collectors.toMap()源码,可以看到,输出的Map是HashMap。
public static <T, K, U>
Collector<T, ?, Map<K,U>> toMap(Function<? super T, ? extends K> keyMapper,
Function<? super T, ? extends U> valueMapper,
BinaryOperator<U> mergeFunction) {
return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
}
而HashMap输出是乱序的。HashMap中的顺序是根据hash值来排序的。
如果想要输出有序,推荐使用LinkedHashMap
。
1.3 LinkedHashMap
LinkedHashMap除实现HashMap,还维护了一个双向链表。LinkedHashMap为每个Entry添加了前驱和后继,每次向linkedHashMap插入键值对,除了将其插入到哈希表的对应位置之外,还要将其插入到双向循环链表的尾部。
在forEach遍历时,HashMap遍历的是tab[]数组,LinkedHashMap遍历的是双向链表,从head开始,即最初的List顺序。
1.4 解决方案
为保证输出有序,选择LinkedHashMap,具体修改方案如下:
list = list.stream()
.collect(Collectors.toMap(Student::getName, Function.identity(),(oldValue,newValue)->newValue,LinkedHashMap::new))
.values().stream().collect(Collectors.toList());
list转map后再转为list的写法,以上为写法一。
写法二:
list = list.stream()
.collect(Collectors.toMap(Student::getName, Function.identity(),(oldValue,newValue)->newValue,LinkedHashMap::new))
.entrySet().stream()
.map(a -> a.getValue())
.collect(Collectors.toList());
除了选择LinkedHashMap解决输出乱序的问题,若list集合中有其他规则可以达到顺序的结果也是可以的,如根据list中id的顺序排序等,达到有序的效果。
2.Collectors.groupingBy() 输出乱序
2.1 场景示例
对list集合以姓名进行分组,输出后却是乱序的
Map<String, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getName));
其原因和Collectors.toMap()类似,查看源码可知Collectors.groupingBy()
输出为HashMap。
public static <T, K, A, D>
Collector<T, ?, Map<K, D>> groupingBy(Function<? super T, ? extends K> classifier,
Collector<? super T, A, D> downstream) {
return groupingBy(classifier, HashMap::new, downstream);
}
2.2 解决方案
选择以LinkedHashMap输出。
Map<String, List<Student>> map = list.stream().collect(Collectors.groupingBy(Student::getName,LinkedHashMap::new,Collectors.toList()));