Java如何检测比较器合同违规?

时间:2015-06-06 03:20:52

标签: java compilation comparator

令我惊讶的是,Java有时可以为您检查比较器合同。

例如,当您编写一个不遵循传递性的订单关系时,您会得到

java.lang.IllegalArgumentException: Comparison method violates its general contract!

如何检查此类违规行为? Java如何实现它?

(如果您不知道我在说什么,请参阅this question

2 个答案:

答案 0 :(得分:2)

当你获得此异常时,你并没有具体说。我假设当您使用自己的Collections.sort作为参数进行Comparator来电时,您会收到此消息,因为我已经能够找到此错误在Java源代码中。

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/TimSort.java#773

(TimSort是用于Collections.sort

的实现

如果Comparator不一致(compare(a,b)的结果与compare(b,a)的结果不一致)或不稳定,则不会返回相同的结果输入,您将在TimSort方法保留的临时状态中获得内部不一致。

该算法检测到此内部不一致并抛出异常:

772        } else if (len1 == 0) {
773            throw new IllegalArgumentException(
774                "Comparison method violates its general contract!");
775        } 

注意当您的比较器违反合同时,无法保证您会收到此异常(这对比较器的单元测试来说很酷)。

您碰巧传递给Collections.sort的特定调用的输入可能不正确,或者Comparator的不一致输出可能不会导致TimSort方法内部不一致。 在这种情况下,结果排序顺序仍然可能不正确,但您无法保证获得例外。

答案 1 :(得分:1)

当然,通过检查您的代码无法证明这一点!

针对特定输入和某些代码分支检测到违规。例如

if( compare(x,y)==0 && compare(y,x)!=0 )
    throw IllegalArgumentException: Comparison method violates its general contract!

只需检查抛出异常的实际来源,例如http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/TimSort.java#772