java 嵌套字段的 Comparator.comparing(...)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38533338/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 03:30:17  来源:igfitidea点击:

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

javalambdajava-8comparator

提问by Geoffrey De Smet

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?

但是我如何在嵌套字段上比较 Lecture,就像这样?

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

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

我无法Lecture.getTeacherAge()在模型上添加方法。

回答by Eran

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

您不能嵌套方法引用。您可以改用 lambda 表达式:

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.

注意:在某些情况下,您需要明确说明泛型类型。例如,如果没有Java 8 中的<FlightAssignment, LocalDateTime>before comparing(...),下面的代码将无法运行。

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.

较新的 java 版本具有更好的自动类型检测,可能不需要。

回答by Nazarii Bardiuk

Unfortunately there is no nice syntax in java for that.

不幸的是,java 中没有很好的语法。

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);
    
  • 通过组合比较器

    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);
    
  • 通过组合 getter 函数

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

回答by manish garg

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

       }

    }