引言:
本文仅为刚毕业时自己写代码遇到何发现这个问题,然后去想的解决办法的一个过程记录。也并非最优解,很高兴评论区的大佬们,能独立思考,给出更优雅的解决办法。但是本文主要是做一个记录,也不准备再修改文章内容了。借鉴着查看吧
昨天开发的时候,遇到了一个排序的问题,于是乎采用java.util包下面的Comparator.comparing来比较。测试的时候发现了空指针异常,于是乎,找到了它的nullsFirst()和nullsLast()两个方法,两个方法的意思就是,为空的时候,就给放到最前面或者最后面。但是,这两个方法并不可行,还是报错。


开启Debug。
nullsFirst()和nullsLast()方法介绍及出错原因
nullsFirst():
此方法返回比较器,其是空型比较,并认为空值小于非空。null首先通过以下逻辑进行操作:
1.null元素被认为小于non-null(即值是null的小于非空的)。
2.当两个元素都为空时,则认为它们相等。
3.当两个元素都不为空时,指定的Comparator确定顺序。
4.如果指定的比较器为null,则返回的比较器将所有非null元素视为相等。
5.如果指定的比较器可序列化,则返回的比较器可序列化。
nullsLast():
方法返回比较器,其是空型比较,并认为比非空更大空值。null首先通过以下逻辑进行操作:
1.null元素被认为大于非null。
2.当两个元素都为空时,则认为它们相等。
3.当两个元素都不为空时,指定的Comparator确定顺序。
4.如果指定的比较器为null,则返回的比较器将所有非null元素视为相等。
5.如果指定的比较器可序列化,则返回的比较器可序列化。
网上说可以 用这两个东西来避免空指针异常。但是事实并不是,在这里点名感谢w哥,大半夜不赔老婆来帮我分析问题。
看源码我们可以发现,compare是有判空两个比较对象都为空的情况,直接返回0,理论上是没有问题的,但是而debug的时候,发现这两个对象,传过来的就是对象本身,并不是我想比较的两个对象里面的某个字段。

所以这里判空,肯定不是null,从而继续比较,
继续往下我们可以发现,它进入了String 的compareTo()方法,但是可以发现这个方法,本身参数就有一个@NotNull注解,于是乎,当比较的字段为null的时候,就有了空指针异常。

解决办法
知道了原因,再来找解决办法,就有思路了
.filter()过滤
刚开始的时候,我们尝试了在流式操作的时候,用.filter()来过滤掉,字段为空的数据,实际效果也可行,确实解决了空指针异常的问题。
但是运行出来的数据,并不是我们想要的效果
自定义比较器
这个方法也是w哥提供给我的一个思路,但是,写到一半,感觉不太可行,毕竟String 的compareTo()还是有@NotNull标签,这也就意味着要写一大堆if else 自己判空,写出来的代码,很不优雅,over
最终解决方案–自己写个Function
既然它本身是因为为空的时候,有空指针异常,那么我们自己写一个方法不就好了?太伟了
//定义排序规则
Comparator<DeviationByTypeVO> byOne = Comparator
.comparing(mapOrDefault(DeviationByTypeVO::getOneClass));
Comparator<DeviationByTypeVO> byTwo = Comparator
.comparing(mapOrDefault(DeviationByTypeVO::getTwoClass));
Comparator<DeviationByTypeVO> byThree = Comparator
.comparing(mapOrDefault(DeviationByTypeVO::getThreeClass));
Comparator<DeviationByTypeVO> byFour = Comparator
.comparing(mapOrDefault(DeviationByTypeVO::getFourClass));
//联合排序
Comparator<DeviationByTypeVO> finalComparator =
byOne.thenComparing(byTwo).thenComparing(byThree).thenComparing(byFour);
return result.stream().sorted(finalComparator).collect(Collectors.toList());
自定义的mapOrDefault()方法
private Function<DeviationByTypeVO,String> mapOrDefault(Function<DeviationByTypeVO, String> func){
//用Optional来设置默认值,如果为空就设置为你想要的规则,比如我这里,想放最后
//这里比较的因为都是英语单词,Z就是最大的,ASCII码是90,比Z大1的就是91
return vo -> Optional.ofNullable(func.apply(vo)).orElse("91");
}
经实践证明,此方法科学可行,靠谱。

在使用Java的Comparator的nullsFirst()和nullsLast()方法处理排序时,可能会遇到NullPointerException。本文介绍了这两个方法的原理,分析了报错的原因,并提出了解决方案,包括使用.filter()过滤、自定义比较器以及通过自定义的mapOrDefault()方法来避免空指针异常。
779





