Comparator.comparing(...) of a nested field

Geoffrey De Smet picture Geoffrey De Smet · Jul 22, 2016 · Viewed 22.1k times · Source

Suppose I have a domain model like this:

class Lecture {
     Course course;
     ... // getters
}

class Course {
     Teacher teacher;
     int studentSize;
     ... // getters
}

class Teacher {
     int age;
     ... // getters
}

Now I can create a Teacher Comparator like this:

    return Comparator
            .comparing(Teacher::getAge);

But how do I compare Lecture's on nested fields, like this?

    return Comparator
            .comparing(Lecture::getCourse::getTeacher:getAge) 
            .thenComparing(Lecture::getCourse::getStudentSize);

I can't add a method Lecture.getTeacherAge() on the model.

Answer

Eran picture Eran · Jul 22, 2016

You can't nest method references. You can use lambda expressions instead:

return Comparator
        .comparing(l->l.getCourse().getTeacher().getAge(), Comparator.reverseOrder()) 
        .thenComparing(l->l.getCourse().getStudentSize());

Without the need for reverse order it's even less verbose:

return Comparator
        .comparing(l->l.getCourse().getTeacher().getAge()) 
        .thenComparing(l->l.getCourse().getStudentSize());

Note: in some cases you need to explicitly state the generic types. For example, the code below won't work without the <FlightAssignment, LocalDateTime> before comparing(...) in Java 8.

flightAssignmentList.sort(Comparator
        .<FlightAssignment, LocalDateTime>comparing(a -> a.getFlight().getDepartureUTCDateTime())
        .thenComparing(a -> a.getFlight().getArrivalUTCDateTime())
        .thenComparing(FlightAssignment::getId));

Newer java version have better auto type detection and might not require that.