Reputation: 45
First of all, I've already looked at the many questions and answers about this exception but most of them are just about comparing simple integers or the same properties. What I have is an object that has two dates, that when one is null I will use the other one to compare, ex of the class:
public class MyClass {
private LocalDate primaryDate;
private LocalDate secondaryDate;
private String Code;
}
the comparison method is:
private List<MyClass> sortByDates(final List<MyClass> listOfClass) {
Comparator<MyClass> comparator = ((Comparator<MyClass>) (first, second) -> {
if (first.getPrimaryDate() == null || second.getPrimaryDate() == null) {
return first.getSecondaryDate().compareTo(second.getSecondaryDate());
}
return first.getPrimaryDate().compareTo(second.getPrimaryDate());
}).reversed().thenComparing(MyClass::getCodeAsLong);
return listOfClass.stream()
.sorted(comparator)
.collect(Collectors.toList());
}
Obs1: secondaryDate
is never null but I have to use the primaryDate
as first option to compare, and primaryDate
is never less than secondaryDate
Obs2: Code
property is saved as a string but don't have any letter, so it can be converted to long
Upvotes: 1
Views: 1962
Reputation: 8124
The only problem is how your handle null for primaryDate
.
Check the following example:
MyClass | primaryDate | secondaryDate |
---|---|---|
A | null | 1/1/2021 |
B | 1/1/2023 | 1/1/2022 |
C | 1/1/2024 | 1/1/2020 |
By your comparator, B > A and A > C which imply B > C
However when you compare B with C. B < C, this violate the "General Contract".
In general, when comparing nullable field, we can make use of nullsFirst
or nullsLast
:
Comparator<MyClass> comparator = Comparator.nullsFirst(Comparator
.comparing(MyClass::getPrimaryDate))
.thenComparing(MyClass::getSecondaryDate)
.reversed()
.thenComparing(MyClass::getCodeAsLong);
Upvotes: 4