【问题标题】:JAVA_Runtime_Error :- Comparison method violates its general contractJAVA_Runtime_Error :- 比较方法违反了它的一般合同
【发布时间】:2017-05-23 18:00:50
【问题描述】:

我在尝试对节点的数组列表进行排序时遇到此错误。我已经尝试了大多数解决方案,但在我的情况下它们都不起作用。

java.lang.IllegalArgumentException: Comparison method violates its general contract!
at java.util.ComparableTimSort.mergeHi(ComparableTimSort.java:866)
at java.util.ComparableTimSort.mergeAt(ComparableTimSort.java:483)
at java.util.ComparableTimSort.mergeCollapse(ComparableTimSort.java:406)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:213)
at java.util.Arrays.sort(Arrays.java:1312)
at java.util.Arrays.sort(Arrays.java:1506)
at java.util.ArrayList.sort(ArrayList.java:1454)
at j...

代码是

static class Node implements Comparable<Node>
{
    int key;
    int value;
    int double_value;

    public Node(int key , int value , int double_value)
    {
        this.key = key;
        this.value = value;
        this.double_value = double_value;
    }

    public int compareTo(Node node)
    {
        if(double_value < node.double_value)
            return 1;
        else if(double_value > node.double_value)
            return -1;

        return -1;
    }
}

它适用于小输入,但当输入数量很大时,它会出现此错误。我还阅读了比较方法中的传递性规则,但我无法弄清楚它在这种情况下是如何应用的。

提前致谢。

【问题讨论】:

  • 如果两个节点的值相等,则返回 -1,这意味着一个节点可以同时小于和大于另一个节点,具体取决于您比较的顺序。这确实违反了Comparable.compareTo 的合同(就此而言,也违反了常识)。对于比较双精度的简单情况,请改用Double.compare 方法。
  • 您的 compareTo 永远不会返回 0 以表明它们是相同的,并且您还应该覆盖 equals() 以便两个拥有相同 double_value n1.equals(n2) 的节点返回 true。当您覆盖等于时,您还应该覆盖hashcode()
  • 请不要使用下划线!遵循 Java 命名约定并将 double_value 替换为 doubleValue
  • 标识符应该代表目的和角色,而不是(错误地)实现,并且应该根据 Java 命名约定进行拼写。

标签: java collections comparable


【解决方案1】:

由于您实际上是在比较 int 值(尽管它被命名为 double_value),您可以使用一个非常简单的 compareTo 方法

public int compareTo(Node node)
{
    return this.double_value - node.double_value;
}

您不必返回 -1、0 或 +1 — 任何负值或正值都可以。
compareTo() 的文档说:

将此对象与指定对象进行比较以进行排序。返回负整数、零或正整数,因为此对象小于、等于或大于指定对象。

所以

Node node1 = new Node(5, 5, 5);
Node node2 = new Node(7, 7, 7);
System.out.println( node1.compareTo(node2) );

将产生 -2,因为 5 小于 7。

当你覆盖 compareTo 时,你也应该覆盖 .equals(Node other),当你覆盖 equals 时,你应该覆盖 also override hashCode()


根据 Chris Parker 的评论更新以提高安全性,这可以追溯到使用 -1、0、1 的结果:

public int compareTo(Node other)
{
    final long m = (long) this.double_value = (long) other.double_value;
    return m < 0 ? -1 :
           m > 0 ?  1 :
           0;
}

【讨论】:

  • 谨慎使用减法进行比较。根据包含的数字,您可以超过有符号 32 位整数的值,溢出将导致无效返回。
  • 这是真的@Chris ...你最终可能会得到Integer.MIN_VALUE - Integer.MAX_VALUE,它错误地显示为1。你可以投加宽,比如long m = (long)a - (long)b;,让它更安全。
猜你喜欢
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-15
相关资源
最近更新 更多