在学习中很少使用Stream,但在工作中,我多次使用Stream进行排序,上一篇 Java Stream的简单应用中,连入门都算不上,现在,总算是能使用Stream进行一些比较常规特殊的排序了,之所以使用Stream当然是因为方便强大优雅,所以学起来
流排序
List<Map<String, Object>> maps,传入的不是对象集合,而是Map集合,(现在才意识到对象和Map很像,String类型的key,Object的value,就像对象,属性(字段)名为key,如Integer age; key为String类型的age(只是变量名),值为Integer类型(Object类型子类),key-value就是对象的属性名和属性值)
List.sort()方法和Stream.stream().sorted()的区别
我觉得两者在使用上没有大的区别,观其源码,参数是一样的,所以应该在使用上无感知(确实,我一直以为使用的sort()方法是sorted(),导致代码出了个很严重的bug),两者的差异,sort()是对集合本身做操作,会改变集合本身的结构(还是原集合,元素顺序(单只做排序元素本身和排序前是一样的,即元素未发生改变))发生改变,而sorted()不一样,如果不做collect(Collectors.toList())是不会改变原集合的结构的,如下图
注: 强转类型为(Double)是因为值可能为null,null无法转化为基本数据类型,必然抛异常
public static void main(String[] args) {
List<Map<String, Object>> maps = new ArrayList<>();
Map<String, Object> map1 = new HashMap<>();
map1.put("score", 17.0);
map1.put("dealerDistance", 3.0);
Map<String, Object> map2 = new HashMap<>();
map2.put("score", 18.0);
map2.put("dealerDistance", 3.67);
Map<String, Object> map3 = new HashMap<>();
map3.put("score", null);
maps.add(map1);
maps.add(map2);
maps.add(map3);
//排序写法
//Comparator.nullsLast(Comparator.reverseOrder())把null排序最后面,然后是Comparator.reverseOrder(),null值不参与逆序,null还是在最后
List<Map<String, Object>> collect = maps.stream()
//当删去第10行代码时map3中无名称为score的key,会出异常,用下面的注释代码可避免程序异常
//(Map<String, Object> o) -> (o.get("score") == null ? -9999 : (Double) o.get("score")))
.sorted(Comparator.comparing((Map<String, Object> o) -> (Double) o.get("score"),
Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing((Map<String, Object> o) -> ((double) o.get("dealerDistance")),
Comparator.nullsLast(Comparator.naturalOrder())))
.collect(Collectors.toList());
// ------------------------------------------------------------------------------
//当list集合中map元素o中没有这个字段(score)时,吾观其源码,无score key返回null,给其排序数字为-9999),会出异常
//注意这是List类的sort方法,不是Stream类的sorted方法,两者使用上好像没啥不同
//Comparator.nullsLast(Double ::compareTo).reversed() 先是把null排最后面,再整体reversed(),包括为null的,所以null在最前面
maps.sort(Comparator.comparing((Map<String, Object> o) -> ((Double) o.get("score")), Comparator.nullsLast(Double::compareTo).reversed())
.thenComparingDouble((Map<String, Object> o) -> (o.get("dealerDistance") == null ? -9999 : (Double) o.get("dealerDistance"))));
System.out.println(maps);
}
集合元素初始顺序
Stream.sorted()并不操作原集合(maps)
List.sort()后,操作原集合(maps),元素顺序已发生改变
Comparator.nullsLast()和nullsFirst()的使用(两者类似)
以nullsLast()为例(项目逻辑中dealerDistance为null时排最后,以score排序时,score为null时也一样),具体详细看上面代码
Comparator.nullsLast(Comparator.reverseOrder())把null排序最后面,然后是Comparator.reverseOrder(),null值不参与逆序,null还是在最后
Comparator.nullsLast(Double ::compareTo).reversed() 先是把null排最后面,再整体reversed(),包括为null的,所以null在最前面
注:reverseOrder()是逆转排序即逆序,而reversed()是逆转仔细理解,这两个在意思上还是有区别的
sort() and sorted()源码
//List
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
//Stream
Stream<T> sorted(Comparator<? super T> comparator);
各种尝试
以下是为了完成需求而做的各种尝试,以下代码不保证能跑通,也不保证正确,请根据自身业务需求多次调试
/**
* 按分数降序(逆序)排序,分数高的排前,空的排最后,
* 同分以距离(顺序)排序,距离小的排前
* @param maps
* @return
*/
private List<Map<String, Object>> sortByScore(List<Map<String, Object>> maps) {
if (CollectionUtil.isEmpty(maps)) {
return Collections.emptyList();
}
//上面说过Map和对象很像,但建议传递对象,做各种操作都会更加方便,如果是对象,就不需要下面各种探索了
/*List<Map<String, Object>> collect = maps.stream()
.sorted(Comparator.comparing(InfoVO :: getScore , Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing(InfoVO :: getDistanceDouble , Comparator.nullsLast(Comparator.naturalOrder())))
.collect(Collectors.toList());
return collect;*/
------------------------------------------------------------------------------
/*List<Map> collect =
maps.stream().sorted((o1, o2) -> Comparator.reverseOrder().compare((String)o1.get("score"), o2.get("score")))
.collect(Collectors.toList());*/
//Collections.sort(maps, Comparator.comparing(o -> (((Double) o.get("score")))));
//maps.sort(Comparator.comparing(o -> (Double) o.get("score")).reversed());
//maps.sort(Comparator.comparingDouble(o -> (double) o.get("score")));
//List<Map<String, Object>> collect4 = maps.stream().sorted(Comparator.comparing(o -> (Double) o.get("score")).reversed()).collect(Collectors.toList());
------------------------------------------------------------------------------
/*Collections.sort(maps, (o1, o2) -> {
Double score1 = (Double) o1.get("score");
Double score2 = (Double) o2.get("score");
int c = score1.compareTo(score2);
if (c != 0) {
return c;
}
Double dealerDistance1 = (Double) o1.get("dealerDistance");
Double dealerDistance2 = (Double) o2.get("dealerDistance");
return dealerDistance1.compareTo(dealerDistance2);
});*/
------------------------------------------------------------------------------
maps.sort((o1, o2) -> {
Double score1 = (Double) o1.get("score");
Double score2 = (Double) o2.get("score");
//逆序
int c = score2.compareTo(score1);
if (c != 0) {
return c;
}
Double dealerDistance1 = (Double) o1.get("dealerDistance");
Double dealerDistance2 = (Double) o2.get("dealerDistance");
//顺序
return dealerDistance1.compareTo(dealerDistance2);
});
return maps;
}
------------------------------------------------------------------------------
//排序写法
maps.stream().sorted(Comparator.comparing((Map<String, Object> o) -> ((double) o.get("score")),
Comparator.nullsLast(Comparator.reverseOrder()))
.thenComparing((Map<String, Object> o) -> ((double) o.get("dealerDistance")),
Comparator.nullsLast(Comparator.naturalOrder())));
------------------------------------------------------------------------------
//当list集合中map元素o中没有这个字段(score)时,吾观其源码,无score key返回null,给其排序数字为-9999),会出异常
//注意这是List类的sort方法,不是Stream类的sorted方法,两者使用上好像没啥不同
maps.sort(Comparator.comparing((Map<String, Object> o) -> (o.get("score") == null ? -9999 : (Double) o.get("score"))).reversed()
.thenComparingDouble((Map<String, Object> o) -> (o.get("dealerDistance") == null ? -9999 : (Double) o.get("dealerDistance"))));