发布时间:2024-12-13 16:01
在开发的过程中,通常会对一些List
进行排序,如果仅仅对某一个数字型的字段进行排序,排序的种类有很多,无论是使用Java 8 新特性的Stream
排序,或者是使用Array.sort
方法都可以。但有时候我们需要对字符串类型,并且可能会处理null
值、空值,并且进行多字段的排序,这时候一行两行的排序很难解决问题,就需要我们将其单独拿出来,写一个排序比较器,通过这个比较器完成我们的比较逻辑。
Comparator
接口是Java中的一个函数式接口,支持Lambda
表达式,其类似于String
中对两个字符串比较的函数s1.compareTo(s2)
,在这个函数中,如果s1
s1>s2
,此函数将会返回一个正值,如果相等,则返回0
。同样,Comparator也是一样的功能,其就是比较两个对象o1,o2
,如果o1
0
的数字,相等返回0
,o1>o2
返回大于0
的数字。
在开发中有这样的一个业务需求:我需要对数据库查询的结果中,对对象中的字段Zwjb
先进行排序,再对Id
进行排序,排序规则是Zwjb
字段为null
的排在最后,然后对Zwjb
字段按数值进行降序排序,之后再对Id
进行升序排序。其中Zwjb
为字符串类型,Id
为整形。
根据以上条件,我们需要思考如何构造一个比较器,这里使用了Lambda
表达式,如果还没有看过的话可以看一下Lambda
表达式这里贴出一个代码:
// RetConsultInfoVo 有一个对象属性为 GzYg
// GzYg 有一个字符串属性 Zwjb
Comparator<RetConsultInfoVo> myComparator = (o1, o2) -> {
// 若两者都为null,即相等,一定返回0,否则会对之后其他字段的排序造成干扰
if(o1.getGzYg().getZwjb() == null && o2.getGzYg().getZwjb() == null)
return 0;
else if(o1.getGzYg().getZwjb() == null){
// 若o1为null,本应该返回一个负值,此处返回正值,即直接使用就是倒序,不需要再额外指定倒序位。
return 1;
}else if(o2.getGzYg().getZwjb() == null) {
// 此处与上面的内容一样
return -1;
}else{
Double d1,d2;
d2 = Double.parseDouble(o2.getGzYg().getZwjb());
d1 = Double.parseDouble(o1.getGzYg().getZwjb());
// 相等的地方返回0必不可少,与上面两者都是null的考虑一样
if (d1.equals(d2)) {
return 0;
}
else {
return d1 - d2 < 0 ? 1 : -1;
}
}
};
我们的构造器写好了,接下来该如何使用呢?那么看接下来的使用方式,这里使用Stream来对List进行排序:
// consults 是数据库返回的一个List结果,这里对consults列表进行排序
List<RetConsultInfoVo> retConsultInfoVos;
// .sorted() 函数的参数需要一个比较器(排序简单的话使用Comparator.comparing()也可以构造一个比较器),之后可以继续比较别的字段,使用thenComparing()函数即可,
// thenComparing()这个函数里面也是一个比较器,也可以使用自己定义的比较器
retConsultInfoVos = consults.stream().sorted(myComparator.thenComparing((RetConsultInfoVo e) -> e.getGzYg().getId())).collect(Collectors.toList());
在进行复杂的排序时,构造一个比较器时有必要的,因为有可能这个比较器会在多个地方用到,可以减少代码的重复,这个构造器中对一个字段进行了排序,但其配合Stream
,可以直接将顺序变为倒序,非常方便。其二,可以处理复杂的逻辑,可以处理null
值,此处如果直接进行比较的时候,使用nullLast()
函数或者nullFirst()
函数返回的对null
值友好的比较器依然会报空指针错误。