0
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.mergeCollapse(TimSort.java:408)
    at java.util.TimSort.sort(TimSort.java:214)
    at java.util.TimSort.sort(TimSort.java:173)
    at java.util.Arrays.sort(Arrays.java:659)
    at java.util.Collections.sort(Collections.java:217)

Can someone explain why my comparator below sometimes throws the above exception.

Note: The id field in myObject is of type long.

Collections.sort(objectList, new Comparator<MyObject>() {

    @Override
    public int compare(final myObject myobject1, final MyObject myObject2) {

        return (int)(myObject1.getId() - myObject2.getId());

    }
});

Solution:

Based on the answer from @amit

return (int)(Long.compare(myObject1.getId(), myObject2.getId());
user5222688
  • 39
  • 2
  • 8

2 Answers2

4

You might encounter an integer overflow if the ID is relatively high integers in absolute values, which will cause VERY_HIGH_INT - VERY_LOW_INT to be a negative number. This is obviously wrong, and is breaking the contract of the comparator.

Use Integer.compare() (or similarly Long.compare(), Double.compare()...) rather than substracting numbers to avoid it.


EDIT:

Specifically here, the problem is still integer overflow, when casting a long value where its 32 LSbs are in range [2^31,2^32) from long to int, which causes it to be erroneously negative. Demo in ideone.

Solution is the same. Use Long.compare()

Community
  • 1
  • 1
amit
  • 175,853
  • 27
  • 231
  • 333
0

Java 7 has changed the default sort algorithm from MergeSort to TimSort in the java.util.Arrays.sort method.

The sorting algorithm used by java.util.Arrays.sort and (indirectly) by java.util.Collections.sort has been replaced. The new sort implementation may throw an IllegalArgumentException if it detects a Comparable that violates the Comparable contract.

For backward compatibility and to restore the behavior from Java version 6, add new system property- java.util.Arrays.useLegacyMergeSort.

Refer the following link for details -

http://www.oracle.com/technetwork/java/javase/compatibility-417013.html#source

sjain
  • 23,126
  • 28
  • 107
  • 185
  • 1
    While informative, it does not answer the question. The OP is familiar with the contract, and doesn't really cares which sorting algorithm is involved. He cares why the contract in his comparator is broken, and this does not answer it. – amit Aug 13 '15 at 09:26