7.排序比较要慎重
约 954 字大约 3 分钟
实战7:排序比较要慎重
今天介绍的又是一个非常非常基本的基本知识点,为啥要单独拎出来?还是因为这个东西虽然非常简单,但是很容易掉坑,我已经遇到几次不严谨的写法了
1.排序
1.1. Comparator 与 Comparable
输掉排序,这两个接口好像不太容易绕过去,我们简单介绍下它们的区别
- 如果你有一个类,希望支持同类型的自定义比较策略,可以实现接口
Compareable
- 如果某个类,没有实现
Compareable
接口,但是又希望对它进行比较,则可以自自定义一个Comparator
,来定义这个类的比较规则
通过一个简单的实例进行演示说明
public static class Demo implements Comparable<Demo> {
int code;
int age;
public Demo(int code, int age) {
this.code = code;
this.age = age;
}
@Override
public int compareTo(Demo o) {
if (code == o.code) {
return 0;
} else if (code < o.code) {
return -1;
} else {
return 1;
}
}
@Override
public String toString() {
return "Demo{" +
"code=" + code +
", age=" + age +
'}';
}
}
上面的实现中,重点关注 Demo类,实现了Comparable
接口,因此可以直接调用list.sort(null)
来进行比较;
但是如果我们现在需求改变了,希望实现针对demo类的age字段,进行升序排列,那么就可以利用Comparator
来实现了
@Test
public void testDemoSort() {
List<Demo> list = new ArrayList<>();
list.add(new Demo(10, 30));
list.add(new Demo(12, 10));
list.add(new Demo(11, 20));
// 默认根据 code 进行升序比较
list.sort(null);
System.out.println("sort by code: " + list);
list.sort(new Comparator<Demo>() {
@Override
public int compare(Demo o1, Demo o2) {
if (o1.age == o2.age) {
return 0;
} else if (o1.age < o2.age) {
return -1;
} else {
return 1;
}
}
});
System.out.println("sort by age: " + list);
}
输出结果如下
sort by code: [Demo{code=10, age=30}, Demo{code=11, age=20}, Demo{code=12, age=10}]
sort by age: [Demo{code=12, age=10}, Demo{code=11, age=20}, Demo{code=10, age=30}]
1.2. 踩坑预告
再上面的compare方法实现中,我们可以发现里面的实现有点不太美观,我们最终的目的是什么?
- 如果左边的小于右边的,返回 -1
- 如果左边的大于右边的,返回 0
- 如果左边的等于右边的,返回 1
基于此,经常可以看到的实现如下
list.sort(new Comparator<Demo>() {
@Override
public int compare(Demo o1, Demo o2) {
return o1.age - o2.age;
}
});
上面这个实现虽然简洁了,但是有一个致命的问题,可能溢出!!!
所以请注意,千万千万不要用上面这种写法
那么有没有更优雅的方式呢?
- 有,使用基础类的
compare
方法
list.sort(new Comparator<Demo>() {
@Override
public int compare(Demo o1, Demo o2) {
return Integer.compare(o1.age, o2.age);
}
});
上面这一段代码,再jdk1.8中,可以简化为下面一句
list.sort(Comparator.comparingInt(o -> o.age));
再扩展一下,如果希望倒排呢?
- 第一种实现方式,调换位置
- Jdk1.8方式,使用负数
list.sort(new Comparator<Demo>() {
@Override
public int compare(Demo o1, Demo o2) {
return Integer.compare(o2.age, o1.age);
}
});
list.sort(Comparator.comparingInt(o -> -o.age));
2. 小结
今天主要介绍的知识点是排序,再我们日常使用中,如果一个类希望支持排序,最好的方式就是让它实现Comparable
接口,然后自定义排序方式
这样再容器中,如果需要排序,直接调用 list.sort(null)
或者 CollectionUtils.sort(list)
如果目标类没有实现排序接口,或者希望使用另外一种排序方式,则通过自定义的Comparator
来实现
最后关于compare
方法的实现,设计到两个类的比较,这种最终的落脚地,多半是基础类型的比较
- o1 与 o2 比较,返回负数,则最终的结果中o1再前面(即升序排列)
- 不要直接使用
o1-o2
会溢出,推荐使用Integer.compare(o1, o2);
Loading...