java.lang.IllegalArgumentException比较方法违反了其一般合同!在集合中#sort

时间:2014-11-06 10:37:34

标签: java illegalargumentexception

这种例外的原因是什么:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
        at java.util.TimSort.mergeLo(TimSort.java:747)
        at java.util.TimSort.mergeAt(TimSort.java:483)
        at java.util.TimSort.mergeForceCollapse(TimSort.java:426)
        at java.util.TimSort.sort(TimSort.java:223)
        at java.util.TimSort.sort(TimSort.java:173)
        at java.util.Arrays.sort(Arrays.java:659)
        at java.util.Collections.sort(Collections.java:217)
        ...

我使用这样的比较器:

private Comparator<SomeObject> comporator = new Comparator<SomeObject>() {
    public int compare(SomeObject o1, SomeObject o2) {
        return Double.compare(o2.getValue(), o1.getValue());
    }
};

public double getValue() {
    double value = 0;
    for (Parameter parameter : parametrs()) {
        value = value + (parameter.getWeight() * parameter.getSomeValue(this));
    }
    return value;//20.0, 23.0 ...
}

其中parameter.getSomeValue:

public int getSomeValue(SomeObject process) {
    return (int) ((System.currentTimeMillis() - process.getPutTime()) / 1000);
}

在:

public void sort() {
    synchronized (list) {
        Collections.sort(list, comporator);
    }
}

其中:

List<SomeObject> list = new ArrayList<SomeObject>();

我无法重现此异常,但有时会出现这种异常。 另外,您是否可以提供代码示例,在100%的情况下出现此问题?

1 个答案:

答案 0 :(得分:2)

您的比较方法根据getValue()返回的值比较两个对象。由于该值可能会在对同一对象的该方法的连续调用中发生更改,因此可能会导致不一致。似乎价值取决于时间,这是一个坏主意。

假设您将object1与object2进行比较并找出compare(object1, object2) < 0。现在,您将object2与object1进行比较,并找出compare(object2, object1) < 0。这违反了比较方法的合同,因为对象不能比另一个对象更小和更大。由于对getValue的每次调用都会产生不同的结果,这似乎会随着时间的推移而增加,如果确定了所有其他参数,那么稍后调用getValue的对象可能会有更高的getValue() getValue()在两个对象中是相同的。