Can someone explain me in simple terms, why does this code throw an exception, "Comparison method violates its general contract!", and how do I fix it?
private int compareParents(Foo s1, Foo s2) {
if (s1.getParent() == s2) return -1;
if (s2.getParent() == s1) return 1;
return 0;
}
Java does not check consistency in a strict sense, only notifies you if it runs into serious trouble. Also it does not give you much information from the error.
I was puzzled with what's happening in my sorter and made a strict consistencyChecker, maybe this will help you:
You can't compare object data like this:
s1.getParent() == s2
- this will compare the object references. You should overrideequals function
for Foo class and then compare them like thiss1.getParent().equals(s2)
In simple terms, for instance if
compareParents(s1, s2) == -1
thancompareParents(s2, s1) == 1
is expected. With your code it's not always true.Specifically if
s1.getParent() == s2 && s2.getParent() == s1
. It's just one of the possible problems.In our case were were getting this error because we had accidentally flipped the order of comparison of s1 and s2. So watch out for that. It was obviously way more complicated than the following but this is an illustration:
Just because this is what I got when I Googled this error, my problem was that I had
the
value >= other.value
should (obviously) actually bevalue > other.value
so that you can actually return 0 with equal objects.Even if your compareTo is holds transitivity in theory, sometimes subtle bugs mess things up... such as floating point arithmetic error. It happened to me. this was my code:
The transitive property clearly holds, but for some reason I was getting the IllegalArgumentException. And it turns out that due to tiny errors in floating point arithmetic, the round-off errors where causing the transitive property to break where they shouldn't! So I rewrote the code to consider really tiny differences 0, and it worked: