Search code examples
javasortingcollectionscomparator

How to combine parent comparator with child comparator


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 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 >)


Solution

  • 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.