最近一直在做底层方面的研究,所以这段时间就没写java相关的东西,但恰巧今天同事问我一个问题,在帮他解决完这个问题之后,我发现,这个问题对java新手来说还是非常容易犯的,所以在这里记录下。
首先看下面这段代码:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
public class Test {
public static void main(String[] args) {
List<Long> l = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
l.add(ThreadLocalRandom.current().nextLong());
}
l.sort((o1, o2) -> (int) (o1 - o2));
// l.sort(Long::compare);
}
}
这段代码的功能就是对list进行排序,list内元素类型是long。
一眼看上去好像没啥大问题,执行看下:
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.base/java.util.TimSort.mergeLo(TimSort.java:781)
at java.base/java.util.TimSort.mergeAt(TimSort.java:518)
at java.base/java.util.TimSort.mergeCollapse(TimSort.java:448)
at java.base/java.util.TimSort.sort(TimSort.java:245)
at java.base/java.util.Arrays.sort(Arrays.java:1516)
at java.base/java.util.ArrayList.sort(ArrayList.java:1749)
at io.ytcode.game.test/test.Test.main(Test.java:14)
额,报错了(可能需要多执行几次才会报错,但并不影响本文内容),为什么呢?
这段代码大部分逻辑用的都是官方的api,所以这些地方肯定是没问题的,需要我们自己写逻辑的唯一的地方就是list.sort方法传递的参数:Comparator。
看下我们怎么写的,我们返回了 (int) (o1 - o2),看出问题了吗?
o1 - o2的结果还是long啊,如果这个值大于int范围,在我们把它转成int后,结果就溢出处理了,这时,该表达式返回的结果和我们预期的结果就不相同了。
我估计很多人都踩过这坑吧。
那正确的解决方式是什么呢?
把上面程序中的sort行注释掉,用它下面Long::compare的sort行,再试试是不是就可以了。
看下Long::compare的对应实现:
// java.lang.Long
public static int compare(long x, long y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
这才是long的compare的标准方式!
还是那句话,官方库带有的方法就用官方的,这能让你少踩很多坑。
完。
更多原创文章,请关注我微信公众号:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。