I have a parent class
@Data
public class Parent {
private String xx;
private int yy;
}
and two child classes that extends the parent class
@Data
public class ChildA extends Parent {
private String aa;
}
@Data
public class ChildB extends Parent {
private String bb;
}
P.S. for semplicity the fields of Parent and ChildA, ChildB are few, but there are many more.
I have a common comparator:
Comparator<Parent> commonComparator = Comparator.comparing(Parent::getYy)
.thenComparing(Parent::getXx);
and specific comparator for each child:
Comparator<ChildA> childAComparator = Comparator.comparing(ChildA::getAa);
Comparator<ChildB> childBComparator = Comparator.comparing(ChildB::getBb);
If I want to sort the a List of ChildA, how can I combine the commonComparator with the childAComparator ?
I tried :
commonComparator.thenComparing(childAComparator);
but I got an issue:
The method thenComparing(Comparator<? super Parent>) in the type Comparator is not applicable for the arguments (Comparator< ChildA >)
CodePudding user response:
I don't think there is a function in the core libraries that will compose these comparators for you. But it is a simple function:
private static <T> Comparator<T> compose(
Comparator<? super T> before,
Comparator<T> after) {
return (o1, o2) -> {
int diff = before.compare(o1, o2);
return diff == 0 ? after.compare(o1, o2) : diff;
};
}
Then you can use it as
private static final Comparator<ChildA> combined =
compose(commonComparator, childAComparator);
Note that because thenComparing()
has bounds of ? super T
, it can only compose the two comparators when the child comparator is applied first, but in this case, the parent comparator must be applied first.
CodePudding user response:
I don't think there's a better way than casting, even if the common comparator were defined as Comparator<? super Parent>
:
Comparator<ChildA> combinedComparator = ((Comparator) commonComparator)
.thenComparing(childAComparator);
This would compile without errors (and doesn't require casts), but doesn't match your requirements:
childAComparator.thenComparing(commonComparator);
The following works too, but it means your common comparator will only accept ChildA instances (unless casting is performed):
Comparator<ChildA> commonComparator = Comparator.comparing(ChildA::getYy).thenComparing(ChildA::getXx);
commonComparator.thenComparing(childAComparator);