当前位置: 首页 > 知识库问答 >
问题:

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

屠振濂
2023-03-14

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

例如,当您编写不遵循传递性的顺序关系时,您会得到

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

如何能够制止这种违反行为?Java是如何实现的?

(不知道我在说什么就看这个问题)

共有2个答案

步炯
2023-03-14

当然,它不能通过检查你的代码来证明这一点!

对于特定输入和某些代码分支,会检测到冲突。例如

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

许寒
2023-03-14

你没有明确说你什么时候得到这个异常。我假设当您使用您自己的< code >比较器作为参数进行< code>Collections.sort调用时,您会得到这个错误,因为这是我能够在Java源代码中找到这个错误的地方。

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

(TimSort是用于Collections.sort的实现)

当您的比较器不一致(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的特定调用的输入,它可能并不是不正确的,或者比较器的不一致输出可能根本不会导致TimSort方法的内部不一致。在这种情况下,生成的排序顺序仍然可能不正确,但不能保证会得到异常。

 类似资料:
  • 比较器的JavaDoc指出 强烈建议(尽管不是必需的)自然顺序与相等一致。 他们还举了一个“奇怪”行为的例子,当<代码>(a.equals(b) 现在,有人能给我举一个例子说明在case

  • 我知道它已经被询问和回答了数百万次,但我仍然无法弄清楚为什么我在排序期间收到了违规。这是我的代码: 我收到了这个错误 有什么想法吗?

  • 我发现了许多与此标题相关的重复问题,但没有一个与我的问题有关,因为我的问题无法通过崩溃追踪。我不断收到有关此标题的许多不同的崩溃。 检查此示例(仅在android 4上发生): 我通过研究发现,这种情况发生在比较/排序时,而忽略了某个条件。同时,在我的代码中,我没有使用文档/示例中提到的比较或排序方法。 非常感谢任何建议。

  • 我有时会得到一个 for 我可以始终如一地抛出此异常,实时数据运行足够长的时间,但我不确定如何解决问题的实际原因。 我的比较仪有什么问题?(具体来说,我违反了合同的哪一部分?)如何在不掩盖异常的情况下修复它? 我使用的是 Java 7,如果不进行重大重写就无法升级。 我可以通过将设置为来掩盖异常,但这不是一个理想的解决方案。 我尝试创建测试来随机生成数据并验证每个合同条件。我无法抛出异常。 我尝试

  • 有人能解释一下为什么我下面的比较器有时候会抛出上面的异常吗? 注意:myObject 中的 id 字段类型为 long。 解决方案: 基于@amit的回答

  • 问题内容: 有人可以简单地向我解释一下,为什么此代码会引发异常,“比较方法违反了它的一般约定!”,我该如何解决? 问题答案: 你的比较器不是可传递的。 让是的父,并成为母公司。既然和,那一定是这样。但是,如果在和上调用比较器,它将返回零,即。这违反了合同,因此引发异常。 该库可以很好地检测到这一点并让你知道,而不是行为不规律。 满足传递性要求的一种方法是遍历整个链,而不仅仅是查看直接祖先。