每天一个实战小技巧:
排序比较要慎重
今天介绍的又是一个非常非常基本的基本知识点,为啥要单独拎出来?还是因为这个东西虽然非常简单,但是很容易掉坑,我已经遇到几次不严谨的写法了
1. Comparator 与 Comparable
输掉排序,这两个接口好像不太容易绕过去,我们简单介绍下它们的区别
- 如果你有一个类,希望支持同类型的自定义比较策略,可以实现接口
Compareable
- 如果某个类,没有实现
Compareable
接口,但是又希望对它进行比较,则可以自自定义一个Comparator
,来定义这个类的比较规则
通过一个简单的实例进行演示说明
1 | public static class Demo implements Comparable<Demo> { |
上面的实现中,重点关注 Demo类,实现了Comparable
接口,因此可以直接调用list.sort(null)
来进行比较;
但是如果我们现在需求改变了,希望实现针对demo类的age字段,进行升序排列,那么就可以利用Comparator
来实现了
1 | @Test |
输出结果如下
1 | sort by code: [Demo{code=10, age=30}, Demo{code=11, age=20}, Demo{code=12, age=10}] |
2. 踩坑预告
再上面的compare方法实现中,我们可以发现里面的实现有点不太美观,我们最终的目的是什么?
- 如果左边的小于右边的,返回 -1
- 如果左边的大于右边的,返回 0
- 如果左边的等于右边的,返回 1
基于此,经常可以看到的实现如下
1 | list.sort(new Comparator<Demo>() { |
上面这个实现虽然简洁了,但是有一个致命的问题,可能溢出!!!
所以请注意,千万千万不要用上面这种写法
那么有没有更优雅的方式呢?
- 有,使用基础类的
compare
方法
1 | list.sort(new Comparator<Demo>() { |
上面这一段代码,再jdk1.8中,可以简化为下面一句
1 | list.sort(Comparator.comparingInt(o -> o.age)); |
再扩展一下,如果希望倒排呢?
- 第一种实现方式,调换位置
- Jdk1.8方式,使用负数
1 | list.sort(new Comparator<Demo>() { |
3. 小结
今天主要介绍的知识点是排序,再我们日常使用中,如果一个类希望支持排序,最好的方式就是让它实现Comparable
接口,然后自定义排序方式
这样再容器中,如果需要排序,直接调用 list.sort(null)
或者 CollectionUtils.sort(list)
如果目标类没有实现排序接口,或者希望使用另外一种排序方式,则通过自定义的Comparator
来实现
最后关于compare
方法的实现,设计到两个类的比较,这种最终的落脚地,多半是基础类型的比较
- o1 与 o2 比较,返回负数,则最终的结果中o1再前面(即升序排列)
- 不要直接使用
o1-o2
会溢出,推荐使用Integer.compare(o1, o2);
4. 实战系列推荐
- 实战小技巧1:字符串占位替换-JDK版
- 实战小技巧2:数组与list互转
- 实战小技巧 3:字符串与容器互转
- 实战小技巧4:优雅的实现字符串拼接
- 实战小技巧5:驼峰与下划线互转
- 实战小技巧6:枚举的特殊用法
II. 其他
1. 一灰灰Blog: https://liuyueyi.github.io/hexblog
一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛
2. 声明
尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激
- 微博地址: 小灰灰Blog
- QQ: 一灰灰/3302797840
- 微信公众号: 一灰灰blog
3. 扫描关注
一灰灰blog