CodeGym /Kurslar /JAVA 25 SELF /Comparator interfeysi: yaradılması, istifadəsi

Comparator interfeysi: yaradılması, istifadəsi

JAVA 25 SELF
Səviyyə , Dərs
Mövcuddur

1. Giriş

Həyatda obyektləri müqayisə etməyin tək bir üsulu çox vaxt kifayət etmir. Təsəvvür edin ki, sizdə istifadəçilərin siyahısı var: bəzən onları ada görə, bəzən — yaşa görə, bəzən isə — familiyanın uzunluğuna görə sıralamaq istəyirsiniz. Yaxud siz müəllifi olmadığınız bir sinifə sahibsiniz və ona compareTo əlavə etmək mümkün deyil. Məhz belə hallar üçün Java‑da Comparator interfeysi mövcuddur.

Comparable kifayət etmədikdə

  • Sinfi dəyişmək olmur (məsələn, üçüncü tərəf kitabxanasındandır).
  • Bir neçə sıralama üsuluna ehtiyac var (müxtəlif sahələr üzrə).
  • Müqayisə məntiqini sinifdən ayırmaq istəyirsiniz (məsələn, proqramın müxtəlif hissələrində fərqli qaydada sıralamaq).

Analogiya
Əgər Comparable obyektin daxili «təbii qaydası»dırsa, Comparator xarici bir hakimdir; o, obyektlərinizi istənilən meyarla qiymətləndirə bilər: bu gün ada görə, sabah — yaşa görə, birisi gün — adın uzunluğuna görə.

2. Comparator interfeysi: sintaksis və müqavilə

Interfeysin elan edilməsi

public interface Comparator<T> {
    int compare(T o1, T o2);
}

compare metodu aşağıdakıları qaytarmalıdır:

  • Birinci obyekt ikinciyə nisbətən «kiçikdirsə», mənfi ədəd.
  • 0, bərabərdirsə.
  • Birinci «daha böyükdürsə», müsbət ədəd.

Müqavilə Comparable ilə eynidir, sadəcə indi iki obyekt bir‑biri ilə müqayisə olunur, «cari» və «başqa» obyekt isə compareTo vasitəsilə deyil.

Nümunə: familiyaya görə sıralamaq üçün komparator

Tutaq ki, bizdə Person sinfi var:

public class Person {
    private String firstName;
    private String lastName;
    private int age;

    // Konstruktor və getter-lər
    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    public String getFirstName() { return firstName; }
    public String getLastName() { return lastName; }
    public int getAge() { return age; }
}

Familiyaya görə sıralayan komparator yaradaq:

import java.util.Comparator;

public class LastNameComparator implements Comparator<Person> {
    @Override
    public int compare(Person a, Person b) {
        return a.getLastName().compareTo(b.getLastName());
    }
}

Qeyd: sətirlərdə (String) compareTo metodu onları əlifba sırası ilə müqayisə edir.

3. Comparator-dan istifadə: kolleksiyaların sıralanması

Komparatorla sıralama

import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("Anna", "Kostetskaya", 25));
        people.add(new Person("Boris", "Novak", 20));
        people.add(new Person("Viktoriya", "Bell", 22));

        // Familiyaya görə sıralama
        Collections.sort(people, new LastNameComparator());

        for (Person p : people) {
            System.out.println(p.getLastName() + " " + p.getFirstName());
        }
    }
}

Nəticə:

Novak Boris
Kostetskaya Anna
Bell Viktoriya

Komparator vasitəsilə yaşa görə sıralama

Sinif artıq ada görə Comparable reallaşdırsa belə, ayrıca komparator — yaşa görə — yarada bilərsiniz:

public class AgeComparator implements Comparator<Person> {
    @Override
    public int compare(Person a, Person b) {
        return Integer.compare(a.getAge(), b.getAge());
    }
}

Və oxşar şəkildə istifadə etmək:

Collections.sort(people, new AgeComparator());

Nəticə:

Boris Novak (20)
Viktoriya Bell (22)
Anna Kostetskaya (25)

Nümunə: komparatorun «yerindəcə» seçilməsi

Collections.sort(people, new LastNameComparator()); // Familiyaya görə
Collections.sort(people, new AgeComparator());      // Yaşa görə

4. Anonim siniflər və lambda ifadələri

Komparatorları ayrıca sinif elan etmədən «yerindəcə» yaratmaq olar.

Anonim sinif

Collections.sort(people, new Comparator<Person>() {
    @Override
    public int compare(Person a, Person b) {
        return a.getFirstName().compareTo(b.getFirstName());
    }
});

Lambda ifadəsi

Collections.sort(people, (a, b) -> a.getFirstName().compareTo(b.getFirstName()));

Yaxud daha qısa — siyahının List.sort metodu ilə:

people.sort((a, b) -> a.getFirstName().compareTo(b.getFirstName()));
  • Anonim siniflər — köhnə üsuldur, həcmli və uzundur.
  • Lambda — müasir və yığcamdır.

5. Nümunələr: müxtəlif meyarlara görə sıralama

Familiyanın uzunluğuna görə sıralama

Comparator<Person> byLastNameLength = (a, b) ->
        Integer.compare(a.getLastName().length(), b.getLastName().length());
people.sort(byLastNameLength);

Əvvəl yaşa, sonra ada görə sıralama (çoxsəviyyəli)

Comparator<Person> byAgeThenName = (a, b) -> {
    int cmp = Integer.compare(a.getAge(), b.getAge());
    if (cmp != 0) return cmp;
    return a.getFirstName().compareTo(b.getFirstName());
};
people.sort(byAgeThenName);

Axtarış üçün komparatorun istifadəsi (nümunə)

Komparator təkcə sıralama üçün deyil, həm də sıralanmış kolleksiyalarda axtarış üçün uyğundur:

// people siyahısı yaşa görə sıralanmış olmalıdır!
Person key = new Person("?", "?", 22);
int idx = Collections.binarySearch(people, key, new AgeComparator());
if (idx >= 0) {
    System.out.println("Yaşı 22 olan şəxs tapıldı: " + people.get(idx));
}

6. Ən yaxşı təcrübələr və Comparator ilə işin xüsusiyyətləri

Müqaviləni pozmayın

  • Əgər compare(a, b) 0 qaytarırsa, onda compare(b, a)0 qaytarmalıdır.
  • Əgər compare(a, b) > 0-dırsa, compare(b, a) < 0 olmalıdır.
  • Mümkün null dəyərləri nəzərə alın (aşağıya baxın).

equals və hashCode haqqında unutmayın

Komparatorlar obyektləri «öz qaydasında» müqayisə etsə də, TreeSet kimi strukturlar və ya TreeMap-də açar axtarışı üçün komparator üzrə müqayisə məntiqinin equals ilə uyğun olması vacibdir. Əks halda gözlənilməz nəticələr ala bilərsiniz: iki müxtəlif obyekt komparatora görə bərabər sayılır, lakin equals üzrə bərabər deyil.

null nəzərə alınmaqla sıralama

Sahələr null ola bilərsə, «hazır» köməkçilərdən istifadə edin:

Comparator<Person> byLastNameNullSafe = Comparator.comparing(
    Person::getLastName,
    Comparator.nullsLast(String::compareTo)
);
people.sort(byLastNameNullSafe);

7. Faydalı incəliklər

Cədvəl: Comparable və Comparator müqayisəsi

Comparable Comparator
Harada reallaşdırılır? Birbaşa sinfin özündə Ayrı sinifdə/lambdada
Metod
int compareTo(T o)
int compare(T o1, T o2)
Neçə variant? Yalnız bir «təbii» İstədiyiniz qədər, hər cür ehtiyac üçün
Tətbiq
Collections.sort(list)
Collections.sort(list, comp)
Başqa (xarici) siniflər üçün mümkündür? Xeyr Bəli

Nümunə: azalan qaydada sıralama

Qaydaları əl ilə tərsinə çevirmək olar:

Comparator<Person> byAgeDesc = (a, b) -> Integer.compare(b.getAge(), a.getAge());
people.sort(byAgeDesc);

Yaxud reversed() köməyi ilə:

Comparator<Person> byAge = Comparator.comparingInt(Person::getAge);
people.sort(byAge.reversed());

8. Comparator ilə işləyərkən tipik səhvlər

Səhv № 1: müqayisə müqaviləsinin pozulması. Əgər compare(a, b)compare(b, a) nəticələrinin işarə etibarilə bir-birinə əks olmalı olduğunu unudursunuzsa və ya təsadüfi dəyərlər qaytarırsınızsa (məsələn, sadəcə fərqi — a.getAge() - b.getAge(), bu, daşma yarada bilər), nəticə proqnozlaşdırılmayan olacaq. Integer.compare istifadə edin, çıxmadan — bu, daha təhlükəsizdir.

Səhv № 2: null dəyərlərin nəzərə alınmaması. Müqayisə etdiyiniz sahələr null ola bilirsə, mütləq bu halı emal edin (məsələn, Comparator.nullsFirst/Comparator.nullsLast vasitəsilə), əks halda ən gözlənilməz anda NullPointerException ala bilərsiniz.

Səhv № 3: qeyri-sabit sıralama meyarları. Əgər komparator eyni obyektlər üçün fərqli dəyərlər qaytarırsa (məsələn, təsadüfi ədəd və ya çox dəyişən sahə istifadə edir), sıralama xaotik davrana bilər.

Səhv № 4: equals ilə uyğunsuzluq. Əgər compare(a, b) == 0, amma a.equals(b) false-dursa, TreeSetTreeMap kimi kolleksiyalar gözlədiyiniz kimi işləməyə bilər. Arzuolunandır ki, komparator üzrə bərabərlik və equals üzrə bərabərlik üst-üstə düşsün.

Səhv № 5: xarici siniflər üçün komparatorsuz sıralama. Əgər Comparable olmayan «xarici» sinifin obyektlərini və Comparator ötürmədən sıralamağa çalışsanız, kompilyasiya xətası alacaqsınız. Açıq komparator ötürün.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Tədbirdə iştirakçıların yaşa görə sıralanması 🧑‍🎓
Tədbirdə iştirakçıların yaşa görə sıralanması 🧑‍🎓
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Konfrans üçün iştirakçıların ad uzunluğuna görə sıralanması 🏷️
Konfrans üçün iştirakçıların ad uzunluğuna görə sıralanması 🏷️
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION