CodeGym /Kurslar /JAVA 25 SELF /Objects sinfi: equals, hashCode, hash metodları

Objects sinfi: equals, hashCode, hash metodları

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

1. Objects sinfi ilə tanışlıq

Mövzuya keçək! Əgər dəyərləri əl ilə null-a qarşı yoxlamaqdan və hər sahə üçün hash hesabı yazmaqdan yorulmusunuzsa, utilit sinif java.util.Objects köməyinizə çatacaq. Onun məqsədi — obyektlərlə işi daha sadə, yığcam və təhlükəsiz etmək.

Bu, həqiqətən, “isveçrə bıçağı”dır: sinif obyektləri bərabərlik üzrə təhlükəsiz müqayisə edə bilir (risksiz, yəni NullPointerException almadan), hash-kodları rahat hesablaya bilir, komparator vasitəsilə müqayisə edir və arqumentləri null-a qarşı yoxlayır.

Objects.equals: null nəzərə alınmaqla təhlükəsiz müqayisə

Sadəcə a.equals(b) yazsanız və a null olsa, NullPointerException alacaqsınız. Əl ilə yoxlamalar həcmli olur. Objects.equals(a, b) bunu sizin yerinizə edir:

  • Hər ikisi null-dırsa — true qaytarır.
  • Yalnız biri null-dırsa — false qaytarır.
  • Hər ikisi null deyilsə — adi equals çağırılır.
import java.util.Objects;

String a = null;
String b = "Java";
System.out.println(Objects.equals(a, b)); // false

String c = null;
System.out.println(Objects.equals(a, c)); // true

String d = "Java";
String e = "Java";
System.out.println(Objects.equals(d, e)); // true

Bu niyə rahatdır? Kod daha qısadır, daha təmizdir və təsadüfi NPE-lərdən qorunur.

2. Objects.hash və hashCode: hash-ın yığcam hesablanması

hashCode-u equals ilə birlikdə yenidən təyin edərkən, xüsusən sahələr çox olanda, səhv etmək asandır. Əl ilə yazılmış kod çox vaxt həcmli və kövrək görünür:

@Override
public int hashCode() {
    int result = 17;
    result = 31 * result + (name != null ? name.hashCode() : 0);
    result = 31 * result + age;
    return result;
}

Objects.hash metodu problemi həll edir — qısa, təhlükəsiz və null dəstəyi ilə:

import java.util.Objects;

public class Person {
    private String name;
    private int age;

    // ... konstruktor, getter-lər və s.

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

Vacib məqam: Objects.hash varargs istifadə edir və massiv yaradır — nadir, yüksək yüklü yerlərdə əl ilə yazılmış hashCode daha sürətli ola bilər. Əksər tətbiqlər üçün fərq əhəmiyyətsizdir.

3. Objects.compare: müqayisəni komparatora həvalə edirik

Bəzən iki obyekt əvvəlcədən hazırlanmış Comparator ilə müqayisə olunmalıdır. comparator.compare(a, b) birbaşa çağırmaq əvəzinə bunu istifadə edə bilərsiniz:

int result = Objects.compare(a, b, comparator);

Bu metod:

  • Obyektlər bərabərdirsə, 0 qaytarır.
  • null-ı istənilən non-null obyektdən “kiçik” hesab edir.
  • Qalan hallarda məntiqi ötürülmüş komparatora həvalə edir.
import java.util.Comparator;
import java.util.Objects;

class Person {
    private String name;
    Person(String name) { 
        this.name = name; 
    }
    public String getName() { 
        return name; 
    }
}

public class Main {
    public static void main(String[] args) {
        Person a = new Person("Anna");
        Person b = new Person("Boris");
        Comparator<Person> byName = Comparator.comparing(Person::getName);

        System.out.println(Objects.compare(a, b, byName)); // <0, çünki "Anna" < "Boris"
        System.out.println(Objects.compare(a, null, byName)); // >0, çünki a != null
        System.out.println(Objects.compare(null, b, byName)); // <0, çünki null < b
        System.out.println(Objects.compare(null, null, byName)); // 0
    }
}

4. Objects.requireNonNull: “görünməyən” səhvlərə qarşı sığorta

Əgər metod yalnız null olmayan dəyərlər qəbul etməlidirsə, bunu dərhal yoxlayın. Objects.requireNonNull sizin mesajınızla birlikdə NullPointerException atacaq:

public void setName(String name) {
    this.name = Objects.requireNonNull(name, "Ad null ola bilməz");
}

5. Nümunə: düzgün equals, hashCode və compareTo reallaşdırılması Objects ilə

import java.util.Objects;

public class Person implements Comparable<Person> {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = Objects.requireNonNull(name, "Ad null ola bilməz");
        this.age = age;
    }

    public String getName() { return name; }
    public int getAge() { return age; }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true; // İstinad üzrə müqayisə
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        // null ilə təhlükəsiz müqayisə
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age); // Yığcam və təhlükəsiz
    }

    @Override
    public int compareTo(Person other) {
        // Əvvəl adı, sonra yaşı müqayisə edirik
        int cmp = name.compareTo(other.name);
        if (cmp != 0) return cmp;
        return Integer.compare(age, other.age);
    }
}

İndi obyektləri HashSet-də saxlamaq, onları HashMap-də açar kimi istifadə etmək, bərabərlik üzrə müqayisə etmək və siyahıları çeşidləmək (məsələn, Collections.sort vasitəsilə) mümkündür.

6. Real tapşırıqlarda tətbiqi: kodun qısalması və səhvlərin azalması

Nümunə: tətbiqdə istifadəçilər siyahısı

Düzgün equals/hashCode cütlüyü sayəsində kolleksiyalarda axtarış proqnozlaşdırıla bilən olur:

import java.util.ArrayList;
import java.util.List;

List<Person> users = new ArrayList<>();
users.add(new Person("Anna", 25));
users.add(new Person("Boris", 30));

Person search = new Person("Anna", 25);
System.out.println(users.contains(search)); // true

Nümunə: nullable sahələrlə iş

Əgər sinifdə null ola bilən sahələr (məsələn, ata adı) varsa, Objects.equals və Objects.hash istifadə edin:

import java.util.Objects;

public class User {
    private String firstName;
    private String middleName; // null ola bilər
    private String lastName;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(firstName, user.firstName)
            && Objects.equals(middleName, user.middleName)
            && Objects.equals(lastName, user.lastName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(firstName, middleName, lastName);
    }
}

7. Cədvəl: Objects sinfinin əsas metodları

Metod Təyinatı İstifadə nümunəsi
Objects.equals(a, b)
İki obyektin null nəzərə alınmaqla təhlükəsiz müqayisəsi
Objects.equals(a, b)
Objects.hash(a, b, ...)
Bir neçə sahə üzrə hash-kodun yığcam hesablanması
Objects.hash(name, age)
Objects.compare(a, b, comparator)
Komparator vasitəsilə müqayisə, null üçün təhlükəsiz
Objects.compare(p1, p2, byNameComparator)
Objects.requireNonNull(obj[, msg])
null yoxlaması, NullPointerException atır
Objects.requireNonNull(name, "Ad null ola bilməz")
Objects.isNull(obj) / Objects.nonNull(obj)
null/non-null yoxlaması (Stream API-də rahatdır)
list.stream().filter(Objects::nonNull)

8. Objects sinfinin metodlarından istifadə zamanı tipik səhvlər

Xəta №1: Objects.equals-dən nullable sahələr üçün istifadə etməyi unutmaq. Sahələri birbaşa equals ilə müqayisə etsəniz, NullPointerException ala bilərsiniz. Objects.equals(middleName, other.middleName) istifadə edin.

Xəta №2: hashCode-da bütün sahələr nəzərə alınmayıb. equals-da iştirak edən sahələr hashCode-da da iştirak etməlidir, əks halda HashSet/HashMap-in davranışı qeyri-proqnozlaşdırılan olacaq.

Xəta №3: əl ilə yazılmış hashCode səhvlidir. Əmsalları saxlamaq və null yoxlamalarını etmək asan deyil. Objects.hash bunu sizin yerinizə edir; sərt performans tələbləri yoxdursa, ondan istifadə edin.

Xəta №4: Objects.requireNonNull-dan sinfin müqaviləsinin tələb etdiyi yerdə istifadə etməmək. Sahə null-a icazə vermirsə, bunu konstruktor/setter-də yoxlayın — səhv dərhal üzə çıxacaq, çağırış stekinin “cənəlliklərində” yox.

Xəta №5: Objects.hash-i massivlər üçün istifadə etmək. Massivlər üçün Arrays.hashCode, iç-içə massivlər üçün isə Arrays.deepHashCode lazımdır; məzmunun müqayisəsi üçün uyğun olaraq Arrays.equals/Arrays.deepEquals mövcuddur.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Kataloqdakı kitablar üçün rəqəmsal iz yaratmaq 📚
Kataloqdakı kitablar üçün rəqəmsal iz yaratmaq 📚
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Tədbir iştirakçılarının adlarına görə sıralanması 🧑‍🤝‍🧑
Tədbir iştirakçılarının adlarına görə sıralanması 🧑‍🤝‍🧑
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION