异常场景
在JDK8环境下,通过实现Comparator接口,对HashMap根据value降序排序
出异常的Comparator
List<MenuInfo> menus = new ArrayList<>();
menuInfos.stream().forEach(menuInfo -> {
if (!menus.contains(menuInfo)){
menus.add(menuInfo);
}
});
return menus.stream().sorted(new Comparator<MenuInfo>() {
@Override
public int compare(MenuInfo o1, MenuInfo o2) {
if (o1.getType() - o2.getType() == 0)
if ((o1.getPid() - o2.getPid()) == 0)
return o1.getZindex() - o2.getZindex();
return o1.getType() - o2.getType();
}
}).collect(toList());
异常信息
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在实现时需要遵照以下约束:
根据约束Comparator实现做如下修改:
List<MenuInfo> menus = new ArrayList<>();
menuInfos.stream().forEach(menuInfo -> {
if (!menus.contains(menuInfo)){
menus.add(menuInfo);
}
});
return menus.stream().sorted(new Comparator<MenuInfo>() {
@Override
public int compare(MenuInfo o1, MenuInfo o2) {
return o1.getZindex() < o2.getZindex() ? -1 : (o1.getZindex() == o2.getZindex()) ? 0 : 1;
}
}).collect(toList());
在JDK7/JDK8文档中对Comparator实现虽然说不严格要求遵循约束,比方说上述出异常的Comparator,在执行时不一定会报异常,但是为了程序稳定性,最好是遵循约束。至于JDK7之后的Comparator底层排序实现算法Timsort原理,可阅读以下几篇文章: