Comparator.comparing(…) a unui câmp imbricate (Programare, Java, Lambda, Java 8, Comparator)

Geoffrey De Smet a intrebat.

Să presupunem că am un model de domeniu ca acesta:

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

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

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

Acum pot crea un comparator de profesori astfel::

    return Comparator
            .comparing(Teacher::getAge);

Dar cum pot compara Lecture’s pe câmpuri imbricate, ca acesta?

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

Nu pot adăuga o metodă Lecture.getTeacherAge() pe model.

Comentarii

  • De ce nu folosiți un lambda? –  > Por njzk2.
  • Ah… acel moment în care îmi dau seama că am pus o întrebare stupidă 🙂 (Nu că ar exista întrebări stupide.) – –  > Por Geoffrey De Smet.
3 răspunsuri
Eran

Nu poți anina referințe de metode. În schimb, puteți folosi expresii lambda:

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

Fără a fi nevoie de ordinea inversă, este chiar mai puțin verbos:

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

Notă: în unele cazuri, trebuie să indicați în mod explicit tipurile generice. De exemplu, codul de mai jos nu va funcționa dacă nu se specifică <FlightAssignment, LocalDateTime> înainte de comparing(...) în Java 8.

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

Versiunile mai noi ale Java au o mai bună detectare automată a tipurilor și s-ar putea să nu fie nevoie de acest lucru.

Nazarii Bardiuk

Din păcate, nu există o sintaxă frumoasă în java pentru asta.

Dacă doriți să reutilizați părți ale comparatorului, pot vedea 2 moduri:

  • prin compunerea comparatorilor

    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);
    
  • prin compunerea funcțiilor 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);
    

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

       }

    }

Comentarii

  • Puteți adăuga un text care să explice cum a rezolvat codul dvs. întrebarea? –  > Por Mark Stewart.
  • Filtrez obiectul persoană cu data maximă de naștere pe baza subobiectului (PersonalDetail-> BirthDate->birthdate) câmp –  > Por manish garg.