1

What can be reason of this exception:

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)
        ...

i use comparator like this:

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 ...
}

where parameter.getSomeValue:

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

in:

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

where:

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

I can't reproduce this exception, but it arises sometimes. Also, can you give code example where this issue appear in 100% of cases?

alexei_b
  • 21
  • 1
  • 3

1 Answers1

2

Your compare method compares two objects based on the value returned by getValue(). Since that value may change in consecutive calls to that method for the same object, this may lead to inconsistencies. It seems the value depends on time, which is a bad idea.

Suppose you compare object1 to object2 and find out that compare(object1, object2) < 0. Now, you compare object2 to object1 and find out that compare(object2, object1) < 0. This violates the contract of the compare method, since an object can't be both smaller and larger than another object. Since each call to your getValue gives a different result, that seems to increase with time, the object got which getValue was called later may have a higher getValue() if all the other parameters that determine getValue() are equal in the two objects.

Eran
  • 387,369
  • 54
  • 702
  • 768