引言
比较器重写compare方法时,报错:Error: java.lang.IllegalArgumentException: Comparison method violates its general contract;
最后经过调试,推测原因可能出现在long转化为int类型数据出现截断现象所致
代码
if (CollectionUtils.isNotEmpty(sealList)) {
Collections.sort(sealList, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
JSONObject o1Obj = JSONObject.parseObject(o1.toString());
JSONObject o2Obj = JSONObject.parseObject(o2.toString());
String cisdate1 = o1Obj.getString("INDATE");
long l1 = DateUtils.date2long(cisdate1, "yyyy-MM-dd HH:mm:ss");
String cisdate2 = o2Obj.getString("INDATE");
long l2 = DateUtils.date2long(cisdate2, "yyyy-MM-dd HH:mm:ss");
out.println(l1);
out.println(l2);
out.println((l2 - l1));
out.println((int)(l2 - l1));
return (int) (l2 - l1);//long转int存在截断风险!违背compare某些规则,比如传递性
//return (l2 - l1)>0 ? 1:(l2 - l1)==0 ? 0 : -1;正确的方式
}
});
.....
原因
以上只是一部分代码,也是最重要的代码,大概意思就是根据时间戳的大小进行排序。但是在调试过程中发现,有些数据明明(l2 - l1)大于零,但但是转化为int后就变为了小于零,这就是数据截断造成的。
因为long类型数据范围为:-2^63 ~ 2^63-1,即-9223372036854774808 ~ 9223372036854774807
有符号int类型数据范围为:-2^31 ~ 2^31-1,即-2147483648 ~ 2147483647
那仅仅是数据截断造成了正负转化为什么造成了Comparison method violates its general contract;的错误呢?
来看一下接口原始的定义:
红线部分粗糙的翻译一下:
一共有三条规则需要遵守,第一条是没有问题的,来看第二条,也就是红框的部分:
以下均为推测
要求必须具有传递性!
接下来进行一次逻辑思考:
实际上A<B,但是因为截断的原因变成了A>B,那么是否存在C>A但是C<B呢,这样就违反了B<A<C传递出来的B<C。
也就是说是否存在一个long值能使得转换后的计算差的int值翻转最终导致C>A但是C<B呢?
我猜测是存在的,因为C这个值可能实际上就是小于A,计算中被截断,这样算出来C就是大于A的,但是B实际是大于C的,计算中没有被截断,还是B>C
见下图: