0

Need to sort some items based on a time stamp/ current hour and/or the name property of the item's person object in alphabetical order. How would I correct the IllegalArgumentException which is thrown in some cases?

    public static final Comparator<Item> sortByTimeAndName = new Comparator<Item>() {

            @Override
            public int compare(Item lhs, Item rhs) {
                if(lhs.getDate() != null && rhs.getDate != null){
                    if (lhs.getDate().getTime() < rhs.getDate().getTime()) {
                        return -1;
                    } else if (lhs.getDate().getTime() == rhs.getDate().getTime()) {
                        if (lhs.getHour() < rhs.getHour()) {
                            return -1;
                        } else if (lhs.getHour() == rhs.getHour()) {
                            if(lhs.getPerson().getName().compareTo(rhs.getPerson().getName()) == 0){
                              // if two persons have same name, sort by person id
                                if (lhs.getPerson().getID() < rhs.getPerson().getID()){
                                    return -1;
                                }
                            }
                            else{
                                return lhs.getPatient().getName().compareTo(rhs.getPatient().getName());
                            }
                        }
                    }
                }else{
                    if (lhs.getHour() < rhs.getHour()) {
                        return -1;
                    } else if (lhs.getHour() == rhs.getHour()) {
                        if(lhs.getPerson().getName().compareTo(rhs.getPerson().getName()) == 0){
                            if (lhs.getPerson().getID() < rhs.getPerson().getID()){
                                return -1;
                            }
                        }
                        else{
                            return lhs.getPerson().getName().compareTo(rhs.getPerson().getName());
                        }
                    }
                }

                return 1;
            }
        };

Stack trace:

Caused by java.lang.IllegalArgumentException: Comparison method violates its general contract!
       at java.util.TimSort.mergeLo(TimSort.java:761)
       at java.util.TimSort.mergeAt(TimSort.java:497)
       at java.util.TimSort.mergeCollapse(TimSort.java:421)
       at java.util.TimSort.sort(TimSort.java:210)
       at java.util.Arrays.sort(Arrays.java:1998)
       at java.util.Collections.sort(Collections.java:1900)
....
Dan
  • 173
  • 2
  • 18
  • 1
    full stack trace of `IllegalArgumentException`, please post it. – xingbin Dec 04 '18 at 13:36
  • 1
    See also [“Comparison method violates its general contract!”](https://stackoverflow.com/questions/8327514/comparison-method-violates-its-general-contract?rq=1) – Mark Rotteveel Dec 04 '18 at 13:42

1 Answers1

0

Assume there are 3 objects of type Item such as:

for a: assume getDate() == null
for b: assume getDate() != null
So the comperartor's result is
assume if (lhs.getHour() < rhs.getHour()) is true then a < b

also

for b: assume getDate() != null
for c: assume getDate() != null
So the comperartor's result is
assume if (lhs.getDate().getTime() < rhs.getDate().getTime()) is true then b < c

also

for a: assume getDate() == null
for c: assume getDate() != null
So the comperartor's result is
assume if (lhs.getHour() > rhs.getHour()) is true then a > c
(because of the final return 1)

As you can see there is a contradiction:
a < b and b < c but a > c

I believe that cases like this violate the comparison method's general contract.

forpas
  • 160,666
  • 10
  • 38
  • 76