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.
A comparator interface is used to order the objects of user-defined classes. A comparator object is capable of comparing two objects of the same class.
The compare MethodIt returns a positive value if obj1 is greater than obj2. Otherwise, a negative value is returned. By overriding compare( ), you can alter the way that objects are ordered. For example, to sort in a reverse order, you can create a comparator that reverses the outcome of a comparison.
Java Comparator interface is used to order the objects of a user-defined class. This interface is found in java. util package and contains 2 methods compare(Object obj1,Object obj2) and equals(Object element).
Field equals() method in Java with Examples This method compares two field objects and returns true if both objects are equal otherwise false. The two Field objects are considered equal if and only if when they were declared by the same class and have the same name and type.
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.
Unfortunately there is no nice syntax in java for that.
If you want to reuse parts of comparator I can see 2 ways:
by composing comparators
return comparing(Lecture::getCourse, comparing(Course::getTeacher, comparing(Teacher::getAge))) .thenComparing(Lecture::getCourse, comparing(Course::getStudentSize)); // or with separate comparators Comparator<Teacher> byAge = comparing(Teacher::getAge); Comparator<Course> byTeacherAge = comparing(Course::getTeacher, byAge); Comparator<Course> byStudentsSize = comparing(Course::getStudentSize); return comparing(Lecture::getCourse, byTeacherAge).thenComparing(Lecture::getCourse, byStudentsSize);
by composing getter functions
Function<Lecture, Course> getCourse = Lecture::getCourse; return comparing(getCourse.andThen(Course::getTeacher).andThen(Teacher::getAge)) .thenComparing(getCourse.andThen(Course::getStudentSize)); // or with separate getters Function<Lecture, Course> getCourse = Lecture::getCourse; Function<Lecture, Integer> teacherAge = getCourse.andThen(Course::getTeacher).andThen(Teacher::getAge); Function<Lecture, Integer> studentSize = getCourse.andThen(Course::getStudentSize); return comparing(teacherAge).thenComparing(studentSize);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With