2

I find it surprising that Java can sometimes check the comparator contract for you.

For example, when you write an order relation that does not follow transitivity, you get

java.lang.IllegalArgumentException: Comparison method violates its general contract!

How is it possible to check such violation? How does Java implement it?


(See this question if you don't know what I'm talking about)

Community
  • 1
  • 1
Yuhuan Jiang
  • 2,616
  • 2
  • 19
  • 21

2 Answers2

3

You didn't specifically say when you get this exception. I assume that you're getting this when you do a Collections.sort call with your own Comparator as an argument, because that's where I've been able to find this error in the Java source code.

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/TimSort.java#773

(TimSort is the implementation used for Collections.sort)

When your Comparator is inconsistent (the result of compare(a,b) is not consistent with the result of compare(b,a)) or not stable - doesn't return the same outcome for the same input, you'll get an internal inconsistency in the temporary state that the TimSort method keeps.

The algorithm detects this internal inconsistency and throws the Exception:

772        } else if (len1 == 0) {
773            throw new IllegalArgumentException(
774                "Comparison method violates its general contract!");
775        } 

Note there is no guarantee that you will get this exception when your Comparator breaks its contract (that would be cool for a unit test of your comparator).

It may simply not be incorrect for the input that you happened to pass to a particular call to Collections.sort, or the inconsistent output of your Comparator may simply not result in an internal inconsistency in the TimSort method. In that case, it's still possible that the resulting sort order is incorrect, but you're not guaranteed to get an exception.

Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
1

Of course, it cannot prove that by inspecting your code!

The violation is detected for specific inputs and in some code branches. For exmaple

if( compare(x,y)==0 && compare(y,x)!=0 )
    throw IllegalArgumentException: Comparison method violates its general contract!

Just check the actual source where the exception is thrown, e.g. http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/util/TimSort.java#772

ZhongYu
  • 19,446
  • 5
  • 33
  • 61