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.
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);
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
class Person {
String name ;
PersonalDetail pDetail;
public Person(String name, PersonalDetail pDetail) {
super();
this.name = name;
this.pDetail = pDetail;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public PersonalDetail getpDetail() {
return pDetail;
}
public void setpDetail(PersonalDetail pDetail) {
this.pDetail = pDetail;
}
}
class PersonalDetail{
BirthDate birthDate;
public BirthDate getBirthDate() {
return birthDate;
}
public void setBirthDate(BirthDate birthDate) {
this.birthDate = birthDate;
}
public PersonalDetail(BirthDate birthDate) {
super();
this.birthDate = birthDate;
}
}
class BirthDate {
public String getBirthdate() {
return birthdate;
}
public void setBirthdate(String birthdate) {
this.birthdate = birthdate;
}
String birthdate;
public BirthDate(String birthdate) {
super();
this.birthdate = birthdate;
}
}
public class Test1 {
public static void main(String[] args) {
BirthDate b1 = new BirthDate("2019-08-08");
BirthDate b2 = new BirthDate("2025-09-09");
BirthDate b3 = new BirthDate("2025-09-08");
BirthDate b4 = new BirthDate("2024-09-08");
PersonalDetail pd1 = new PersonalDetail(b1);
PersonalDetail pd2 = new PersonalDetail(b2);
PersonalDetail pd3 = new PersonalDetail(b3);
PersonalDetail pd4 = new PersonalDetail(b4);
Person p1 = new Person("P1",pd1);
Person p2 = new Person("P2",pd2);
Person p3 = new Person("P3",pd3);
Person p4 = new Person("P4",pd4);
List<Person> persons = new ArrayList();
persons.add(p1);
persons.add(p2);
persons.add(p3);
persons.add(p4);
Function<Person, PersonalDetail> getCourse = Person::getpDetail;
Person minByAge = persons.stream()
.max(Comparator.comparing(getCourse.andThen(PersonalDetail::getBirthDate).andThen(BirthDate::getBirthdate))).get();
System.out.println(maxByAge.getName());
}
}
来源:https://stackoverflow.com/questions/38533338/comparator-comparing-of-a-nested-field