Reputation: 10335
I'm tyring to sort an array of items in which an item should be brought to the beginning of the array if its id equals the id of a selected item (also belonging to the array). The sorting order of the rest of the elements is their distance from a given location.
I'm experiencing the dreaded java.lang.IllegalArgumentException: Comparison method violates its general contract!
exception in my custom comparator, implemented like this:
Location location = ...; // may be null
Item selectedItem = ...; // may be null or an element of the array to be sorted
private final Comparator<Item> comparator = new Comparator<Item>() {
@Override
public int compare(Item p1, Item p2) {
// if p1 is the currently selected item, bring p1 to the top
// if p2 is the currently selected item, bring p2 to the top
// else sort p1 and p2 by their distance from location
if (selectedItem != null) {
if (selectedItem.getId() == p1.getId()) { //id's are int and unique in the array
return -1;
} else if (selectedItem.getId() == p2.getId()) {
return 1;
}
}
if (location != null) { //location is an Android Location class instance
Float distance1 = location.distanceTo(p1.getLocation());
Float distance2 = location.distanceTo(p2.getLocation());
return distance1.compareTo(distance2);
} else {
return 0;
}
}
};
I don't have an exact sequence to replicate the issue, but all observations of the error so far happen when selectedItem
and location
are not null (they may be both null).
Any hints?
Thanks
Upvotes: 1
Views: 242
Reputation: 10083
I think there's a hint to be found in the answer to this question: https://stackoverflow.com/a/8327575/338479
There are rules (the "contract") for comparators. One is that an object always compare equal to itself (compare()
returns 0). Another is that if A>B and B>C, then A>C. Another is that B>A return the opposite result from A>B.
I'm not seeing any obvious violation to these rules in your comparator, but I'm not privy to the inner workings of your other code. Are there cases where your distanceTo()
method could be violating the rules of this contract?
Is there any chance that location or selectedItem could be changing in the middle of the sort?
Upvotes: 0
Reputation: 78690
I believe your issue is in the fact that, when equal to selectedItem
, you do not return 0 when the two elements being compared are equal. In this way, comparing x
to y
will say x
is greater, but comparing y
to x
says y
is greater (assuming x
and y
are both equal to selectedItem
). This can't be.
if (p1.getId() == p2.getId()) return 0;
Upvotes: 1