Java 另一种“比较法违反了它的总合同!”

Java 另一种“比较法违反了它的总合同!”,java,java-7,comparator,illegalargumentexception,Java,Java 7,Comparator,Illegalargumentexception,作为实习的一部分,我被要求调查一个bug。 一段代码正在抛出 java.lang.IllegalArgumentException:比较方法违反了它的一般约定 自定义比较器通过查看所述自定义类的长成员变量来比较两个自定义类: return v1 > v2 ? -1 : v1 < v2 ? 1 : 0; 我想你找错人了。这段代码不会引发该异常。我希望看到堆栈跟踪,并且我还希望看到ACustomClass.equals方法。除非它测试getAlong结果的相等性,否则它不同意这个比较器

作为实习的一部分,我被要求调查一个bug。 一段代码正在抛出

java.lang.IllegalArgumentException:比较方法违反了它的一般约定

自定义比较器通过查看所述自定义类的长成员变量来比较两个自定义类:

return v1 > v2 ? -1 : v1 < v2 ? 1 : 0;

我想你找错人了。这段代码不会引发该异常。我希望看到堆栈跟踪,并且我还希望看到ACustomClass.equals方法。除非它测试getAlong结果的相等性,否则它不同意这个比较器,因此如果在需要与equals保持一致的上下文中使用,其中一个是错误的,例如排序集合,这更可能是异常产生的地方


你可以通过实验来解决这种怀疑。除非他们能拿出一个实际的正式理由来解释它为什么不起作用,否则你当然有权尝试它。

我认为你找错地方了。这段代码不会引发该异常。我希望看到堆栈跟踪,并且我还希望看到ACustomClass.equals方法。除非它测试getAlong结果的相等性,否则它不同意这个比较器,因此如果在需要与equals保持一致的上下文中使用,其中一个是错误的,例如排序集合,这更可能是异常产生的地方


你可以通过实验来解决这种怀疑。除非他们能拿出一个实际的正式理由来解释为什么它不能工作,否则你当然有权尝试它。

我看不出所展示的比较器有任何明显的错误。我对提议的修复方案持怀疑态度:我觉得它们有巫毒编程的味道

但是如果ACustomClass类的“沿”属性是可变的。。。当你分类的时候它变了。。。然后,这可能会导致排序代码认为比较器违反了契约

所以。。。检查这是否可能是并发问题,其中一个线程正在对另一个线程尝试排序的数组中的对象进行变异

我们花了相当多的时间在这个问题上,包括调试器…许多不同的测试用例。无法复制该行为


我会将其视为指向并发性问题的证据…

我看不出所展示的比较器有任何明显的错误。我对提议的修复方案持怀疑态度:我觉得它们有巫毒编程的味道

但是如果ACustomClass类的“沿”属性是可变的。。。当你分类的时候它变了。。。然后,这可能会导致排序代码认为比较器违反了契约

所以。。。检查这是否可能是并发问题,其中一个线程正在对另一个线程尝试排序的数组中的对象进行变异

我们花了相当多的时间在这个问题上,包括调试器…许多不同的测试用例。无法复制该行为


我会将其视为指向并发性问题的证据…

您是否有可能发布一些实际的代码?您说您在复制此问题时遇到困难,但您也说您知道哪段代码引发了异常。它是哪一个?关于等式的一致性有一些注释。我想说,如果当equals返回false时比较器返回0,或者当equals返回true时比较器返回非零,那么你可能会陷入麻烦。为什么不在这里使用呢?继续我之前的评论:我快速查看了运行时源代码,消息来自TimSort或ComparableTimSort。这些类似乎没有直接调用equals,但它们可能调用了使用equals的其他类。但是我需要做大量的工作来深入研究这个问题。你有没有可能发布一些实际的代码?你说你在重现这个问题上有困难,但你也说你知道哪段代码引发了异常。它是哪一个?关于等式的一致性有一些注释。我想说,如果当equals返回false时比较器返回0,或者当equals返回true时比较器返回非零,那么你可能会陷入麻烦。为什么不在这里使用呢?继续我之前的评论:我快速查看了运行时源代码,消息来自TimSort或ComparableTimSort。这些类似乎没有直接调用equals,但它们可能调用了使用equals的其他类。但是我需要做大量的工作来深入研究这个问题。equals不一定要和comparator一致。Arrays.sort不使用equals。@arshajii在Javadoc中没有这样说,但它确实说,在使用能够施加顺序不一致的比较器时,应该谨慎
ent与等于可对已排序集或已排序映射进行排序。如果我们查看源代码,它也不会抛出异常。equals不必与comparator一致。Arrays.sort不使用equals。@arshajii在Javadoc中没有这样说,但它确实说,当使用能够施加与equals不一致的排序的比较器对排序集或排序映射进行排序时,应该谨慎。如果我们偷看源代码,它也不会抛出异常。确切的IllegalArgumentException:Comparison方法违反了它的一般约定!只有在Java7中,当按照自然顺序排序时,才会出现TimSort。使用比较器时不应该出现这种特定的信息。我不认为这是真的,@MarkoTopolnik@StephenC-谢谢你的洞察力。我们运行了一些测试,看看这是否是事实,看起来您是正确的。@bond-排序函数不应该假设对象是不可变的。-必须这样!从数学上讲,不可能对排序关系正在改变的对象集合进行排序。这不是JDK中的设计缺陷。这是应用程序中的一个设计缺陷,正试图做到这一点。。。这是不可能的事情。好吧,排序方法的JavaAPI契约并不能很好地进行排序。这是为了精确排序,而且一直如此。如果你想/需要足够好的排序,你需要实现你自己的排序方法。确切的IllegalArgumentException:Comparison方法违反了它的一般约定!只有在Java7中,当按照自然顺序排序时,才会出现TimSort。使用比较器时不应该出现这种特定的信息。我不认为这是真的,@MarkoTopolnik@StephenC-谢谢你的洞察力。我们运行了一些测试,看看这是否是事实,看起来您是正确的。@bond-排序函数不应该假设对象是不可变的。-必须这样!从数学上讲,不可能对排序关系正在改变的对象集合进行排序。这不是JDK中的设计缺陷。这是应用程序中的一个设计缺陷,正试图做到这一点。。。这是不可能的事情。好吧,排序方法的JavaAPI契约并不能很好地进行排序。这是为了精确排序,而且一直如此。如果您想要/需要足够好的排序,您需要实现自己的排序方法。
Arrays.sort(anArray, new Comparator<ACustomClass>() {
  @Override
  public int compare(ACustomClass o1, ACustomClass o2) {
    long v1 = o1.getALong();
    long v2 = o2.getALong();
    return v1 > v2 ? -1 : v1 < v2 ? 1 : 0;
  }});