Java排序Comparator实现接口发生异常
异常场景
在JDK8环境下,通过实现Comparator接口,对HashMap根据value降序排序
出异常的Comparator
private static class ValueComparator implements Comparator<Map.Entry<String, Long>> {
public int compare(Map.Entry<String, Long> m, Map.Entry<String, Long> n) {
return n.getValue() > m.getValue() ? 1 : -1;
}
}
异常信息
java.lang.IllegalArgumentException: Comparison method violates its general contract!
异常原因
JDK7/JDK8的Collections.Sort方法实现中,如果两个值是相等的,那么compare方法需要返回0,否则 **可能** 会在排序时抛错,而JDK6是没有这个限制的。
不同版本JDK中Comparator约束差异
在 JDK7/JDK8(当前JDK8),Comparator 要满足自反性
、传递性
、对称性
,不然 Arrays.sort,Collections.sort 会报 IllegalArgumentException 异常。(JDK7 Comparator,JDK8 Comparator)
说明:
1) 自反性:x,y 的比较结果和 y,x 的比较结果相反。
2) 传递性:x>y,y>z,则 x>z。
3) 对称性:x=y,则 x,z 比较结果和 y,z 比较结果相同。
Comparator在实现时需要遵照以下约束:
sgn(x):=⎧⎩⎨⎪⎪⎪⎪−1,0,1,if x < 0if x = 0if x > 0
根据约束Comparator实现做如下修改:
private static class ValueComparator implements Comparator<Map.Entry<String, Long>> {
public int compare(Map.Entry<String, Long> m, Map.Entry<String, Long> n) {
long x = n.getValue().longValue();
long y = m.getValue().longValue();
return (x < y) ? -1 : ((x == y) ? 0 : 1);
//可以直接使用compareTo方法
//return n.getValue().compareTo(m.getValue());
}
}
在JDK7/JDK8文档中对Comparator实现虽然说不严格要求遵循约束,比方说上述出异常的Comparator,在执行时不一定会报异常,但是为了程序稳定性,最好是遵循约束。至于JDK7之后的Comparator底层排序实现算法Timsort原理,可阅读以下几篇文章: