在JDK1.7之后,ArrayList的默认排序方式做了修改,使用TimeSort排序算法来排序
但是,此排序算法比老版本的算法多了如下几个限制条件,如果不注意,排序可能会抛异常
1. 自反性,compare(x, y) = - compare(y, x)
2. 传递性,如果compare(x, y) > 0, compare(y, z) > 0, 则必须保证compare(x, z) > 0
3. 对称性, 如果compare(x, y) == 0, 则必须保证compare(x, z) == compare(y, z)
如果不满足以上3个条件,TimeSort并不是一定会报错,在某些序列条件下才会报错,这与TimeSort的排序逻辑有关。同时只有在排序序列长度在32以上时才有可能抛异常,因为在排序序列长度小于32时,TimeSort会直接退化为二分排序
JDK1.7之后的标准排序方式如下,以长整形为例,其它对象类似:(此处没考虑为Null的情况,如果有可能为null,代码逻辑要保证满足上述的三个条件)
@Override
public int compare(Long a, Long b) {
return a == b ? 0 : (a > b ? 1 : -1);
}
常见的几种错误排序方式(JDK1.7之前可以使用,1.7之后可能会异常)
1. 未判断相等的情况,及不满足自反性
@Override
public int compare(Long a, Long b) {
return a > b ? 1 : -1;
}
此处未判断相等的情况,如果 x==y, compare(x, y) = -1, compare(y, x) == -1, 即compare(x, y) == compare(y, x)
附上一个会抛异常的序列:
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-2,1,0,-2,0,0,0,0}
2. 不满足传递性
@Override
public int compare(Long a, Long b) {
return (int)(a-b);
}
此写法存在溢出的可能,当有溢出发生时,可能会导致传递性不满足,从而会报错。如下可以看到 :
x > y, y > z, 但是 x < z
附上一个会抛异常的序列:
{1145134726, -682584886, 1895454242, 2004378087, -1855696367, 1813048944, -1506811635, -1271811878, 1612219267, 838774780, -1749593269, -1721719275, 1908610116, 1732597731, 958982535, -937016328, 122618972, 775687877, -466649843, 1212803556, 2141188937, -1192216148, 815915713, 2001074718, 590322195, 1498442902, 1985922385, 417233400, 1631605406, -1900707536, -1345360210, -1732308942, -287293378};