user5222688
user5222688

Reputation: 39

Comparison method violates its general contract! Java7 Comparator

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());

Upvotes: 0

Views: 2785

Answers (2)

amit
amit

Reputation: 178481

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

Upvotes: 4

sjain
sjain

Reputation: 23354

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

Upvotes: 0

Related Questions