2

So I've got a line of code like the following:

Collections.sort(lists, new SpecificComparator());

Works fine. But when I try to get it in descending order...

Collections.sort(lits, Collections.reverseOrder(new SpecificComparator()));

... it breaks with the following Exception:

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

When I searched for the Exception message, I found this Q&A, stating that it was because the relationship was not transitive. I guess I'm a little confused on how a relationship can be transitive in one direction and not in the other. My understanding of transitivity is A == B && B == C -> A == C, so...

Here's my comparator:

public class SuperComparator implements Comparator<Item> {

    @Override
    public int compare(Item first, Item second) {
        Result a = first.getResult();
        Result b = second.getResult();
        if(a == null && b == null) return 0;
        if(b == null || b == Result.DISQUALIFIED) return 1;
        if(a == null || a == Result.DISQUALIFIED) return -1;
        return b.getIntValue() - a.getIntValue();
    }

}

...

public class SpecificComparator extends SuperComparator {

    @Override
    public int compare(Item first, Item second) {

        int rank = super.compare(first, second);

        if(rank != 0) return rank;

        BigDecimal thisAmount = first.getAmount() != null ? first.getAmount() : BigDecimal.ZERO;
        BigDecimal otherAmount = second.getAmount() != null ? second.getAmount() : BigDecimal.ZERO;

        return thisAmount.compareTo(otherAmount);
    }
Community
  • 1
  • 1
asteri
  • 11,402
  • 13
  • 60
  • 84
  • add condition for both `a` and `b` being disqualified, and try t again – user902383 Dec 11 '14 at 15:34
  • @user902383 Wow, that worked! Even though I have no idea why. If you add it as an answer, I'll upvote and accept. :) – asteri Dec 11 '14 at 15:41
  • It's also because you used && - if the first expression is false the second doesn't get executed. Vice versa for || – MihaiC Dec 11 '14 at 16:55

2 Answers2

4

If both of your items are disqualified, your comparator will always return 1, and that is wrong.

add check for case when both your items are disqualified and your problem will be solved

user902383
  • 8,420
  • 8
  • 43
  • 63
1

Your comparator is certainly not transitive.

Ensure that for 3 items A, B and C, if A > B and B > C, then A > C ; then you'll be fine

ngasull
  • 4,206
  • 1
  • 22
  • 36