CodeGym /Kurslar /JAVA 25 SELF /Record: sintaksis, üstünlüklər

Record: sintaksis, üstünlüklər

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

1. «DTO-siniflər» problemi: bizə record-siniflər niyə lazımdır?

Düzünü deyək: bu cür sinfi nə qədər dəfə yazmısınız?


public class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Point point = (Point) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }

    @Override
    public String toString() {
        return "Point{" + "x=" + x + ", y=" + y + '}';
    }
}

Guya çətin deyil, amma sətirləri sayın! İndi təsəvvür edin ki, sizdə belə 10 sinif var və hər birində 5–6 sahə. Hətta IDE belə bu şablon kodu generasiya etməkdən yorulur. Və əgər yeni sahə əlavə etmək qərarına gəlsəniz — konstruktoru, getter-i, equals, hashCode, toString metodlarını dəyişməli olacaqsınız... Darıxdırıcı, rutin və səhv mənbəyi.

Belə siniflərə DTO (Data Transfer Object) və ya Value Object deyilir. Onlar sadəcə məlumat saxlayır — vəssalam. Amma şablon kod səbəbindən onları dəstəkləmək çətindir.

Əgər sizə elə gəlirsə ki, bu problem deyil, sadəcə belə 50 sinfi birdən dəyişməli olacağınız vaxtı gözləyin. Onda record-siniflərini xüsusi rəğbətlə xatırlayacaqsınız!

2. Record-a giriş: sintaksis və Java 16+-ın sehrləri

Java 16 ilə hər şey dəyişdi. Yeni sinif növü — record yarandı. Onlar sadəcə verilənlər dəstini saxlamaq lazım olan hallar üçün xüsusi yaradılıb. Sintaksis — digər dillərdəki kortej kimidir.

Record necə elan edilir?


public record Point(int x, int y) { }

Və... vəssalam! Siz indicə iki sahəsi, konstruktoru, getter-ləri, equals, hashCodetoString olan dəyişməz sinif yaratdınız. Artıq yazısız.

Java «qapağın altında» nə edir?

  • Sahələr xy private final olur.
  • Getter-lər avtomatik yaradılır: int x()int y().
  • Konstruktor: public Point(int x, int y).
  • equals/hashCode: bütün sahələri dəyərə görə müqayisə edir.
  • toString: "Point[x=1, y=2]" kimi sətri qaytarır.

Belə demək olar ki, record — «steroidli DTO»dur: daha az kod, daha çox zəmanət, daha az xəta.

Dəyişməzlik (immutability)

Record-sinifinin bütün sahələri avtomatik final olur. Obyekt yaradıldıqdan sonra onu dəyişmək olmaz — bunu kompilyator təmin edir.

Əgər setter əlavə etməyə və ya sahəni final etməməyə çalışsanız — kompilyator sizi saxlayacaq. Sizin rahatlığınıza belə qayğı nadir hallarda rast gəlinir!

3. Record-sinifindən istifadə nümunəsi

Adi sinif (çox kod):


public class Client {
    private final String name;
    private final int id;

    public Client(String name, int id) {
        this.name = name;
        this.id = id;
    }

    public String getName() { return name; }
    public int getId() { return id; }

    // equals, hashCode, toString ...
}

Record sinfi (bir sətir!):


public record Client(String name, int id) { }

İstifadə:


public class Main {
    public static void main(String[] args) {
        Client client = new Client("İvan", 123);
        System.out.println(client.name()); // İvan
        System.out.println(client.id());   // 123
        System.out.println(client);        // Client[name=İvan, id=123]
    }
}

Diqqət edin:
- Sahələrə giriş metodlarının adı sahələrin öz adı kimidir: name(), id().
- setName() və ya setId() yoxdur — obyekt yaradıldıqdan sonra dəyişdirilə bilməz.

4. Record-siniflərinin üstünlükləri: daha az kod, daha az səhv

Daha az kod — daha çox xoşbəxtlik

40 sətir yazmağa nə ehtiyac var, bir sətirlə də etmək olar! Record-sinifləri vaxtı və əsəbləri qoruyur, xüsusən çoxlu DTO və value obyektləri olan böyük layihələrdə.

Dəyişməzlik “kontrakt” üzrə

  • Record-sinifləri həmişə final və dəyişməzdir.
  • Obyekti saxtalaşdırmaq və ya təsadüfən dəyişmək mümkün deyil.
  • Obyektin vəziyyətinin gözlənilməz yerdə dəyişməsindən doğan « qəribə » xətalar yoxdur.
  • Çoxaxınlı proqramlarda təhlükəsiz istifadə oluna bilər (bütün sahələr də immutable olduqda).

equals/hashCode/toString-un avtomatik generasiyası

Müqayisə, hash hesablama və səliqəli çıxış metodlarını əllə yazmağa ehtiyac yoxdur. Hər şey avtomatik və düzgün edilir.


Client c1 = new Client("Anna", 42);
Client c2 = new Client("Anna", 42);

System.out.println(c1.equals(c2));                 // true
System.out.println(c1.hashCode() == c2.hashCode()); // true
System.out.println(c1);                             // Client[name=Anna, id=42]

Kolleksiyalar və açarlar üçün ideal

Record-obyektləri HashMap-də açar, HashSet-də element və s. kimi istifadə etmək olar — hər şey düzgün işləyəcək, çünki equalshashCode bütün sahələri nəzərə alır.


import java.util.HashMap;
import java.util.Map;

Map<Client, String> clients = new HashMap<>();
clients.put(new Client("Anna", 42), "VIP");

System.out.println(clients.get(new Client("Anna", 42))); // VIP

Məlumatların açıq təsviri

Record-sinfisinin sintaksisi dərhal hansı məlumatların saxlandığını və obyektin dəyişməz olduğunu göstərir. Bu, kodu digər tərtibatçılar üçün (və altı ay sonra sizin üçün) daha anlaşılan edir.

5. Cədvəl: adi sinif və record sinfinin müqayisəsi

Adi sinif Record sinfi
Sintaksis Çox kod Bir sətir
Dəyişməzlik Əl ilə təmin edilməlidir Kompilyator tərəfindən təmin olunur
Metodların avtomatik generasiyası Yoxdur Bəli (equals, hashCode, toString)
Sahə əlavə etmək Bəli Yalnız record komponentləri
İrsiyyət İrs almaq olar Həmişə final, irs almaq olmaz
Kolleksiyalarda istifadə Metodları düzgün reallaşdırmaq lazımdır «Qutudan çıxan kimi» işləyir

6. Tədris tətbiqini inkişaf etdirək: record sinfi ilə nümunə

Tutaq ki, tədris bank tətbiqinizdə hesab əməliyyatlarını saxlamaq lazımdır: tarix, məbləğ, əməliyyatın tipi (məsələn, «mədaxil» və ya «çıxarış»).

Java 16-dan əvvəl:


public class Transaction {
    private final LocalDate date;
    private final double amount;
    private final String type;

    public Transaction(LocalDate date, double amount, String type) {
        this.date = date;
        this.amount = amount;
        this.type = type;
    }

    public LocalDate getDate() { return date; }
    public double getAmount() { return amount; }
    public String getType() { return type; }

    // equals, hashCode, toString ...
}

Java 16 və record ilə:


import java.time.LocalDate;

public record Transaction(LocalDate date, double amount, String type) { }

İstifadə:


Transaction t = new Transaction(LocalDate.now(), 100.0, "deposit");
System.out.println(t);         // Transaction[date=2024-06-01, amount=100.0, type=deposit]
System.out.println(t.amount()); // 100.0

7. Vizualizasiya: record nə yaradır

«Açılmış» record-sinfinə baxaq (təxmini kompilyatorun yaradacağı budur):


public final class Point extends java.lang.Record {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public int x() { return x; }
    public int y() { return y; }

    @Override
    public boolean equals(Object o) { /* sahələr üzrə müqayisə */ }

    @Override
    public int hashCode() { /* sahələr üzrə hesablanma */ }

    @Override
    public String toString() { /* səliqəli çıxış */ }
}

Qısa olaraq: record nə vaxt istifadə olunmalıdır

  • Dəyişməz verilənlər dəstinə malik obyekt lazım olanda.
  • Əl ilə yazmadan «dürüst» equals/hashCode/toString lazım olanda.
  • DTO, Value Object, cütlər, üçlüklər, rəng, nöqtə, interval, kolleksiya üçün açar və s. hazırlayanda.

8. Record-sinifləri ilə işləyərkən tipik səhvlər

Səhv №1: yaradıldıqdan sonra setter əlavə etmək və ya sahəni dəyişmək cəhdi.
Record-sinfi öz sahələrini dəyişməyə imkan vermir. setX(int x) kimi bir metod əlavə etməyə çalışsanız, kompilyator dərhal “olmaz” deyəcək. Eyni şey — sahəni birbaşa dəyişməyə çalışsanız da.

Səhv №2: statik olmayan sahə əlavə etmək cəhdi.
Record-sinfində yalnız komponentlər (record adından sonra mötərizədə göstərilən sahələr) və statik sahələr elan edilə bilər. Adi, statik olmayan sahələr əlavə etmək olmaz — kompilyator buna icazə verməyəcək.

Səhv №3: dəyişən (mutable) məntiq üçün record-dan istifadə.
Record-sinifləri dəyişən vəziyyətli obyektlər üçün nəzərdə tutulmayıb. Yaradıldıqdan sonra nələrisə dəyişmək lazımdırsa — adi sinifdən istifadə edin.

Səhv №4: record-un həmişə final olduğunu unutmaq.
Record-sinfi nə miras alına bilər, nə də onu super sinif etmək olar. Bu məhdudiyyəti pozmağa cəhd kompilyasiya xətası ilə nəticələnəcək. Əsas qayda — record-u «genişləndirməyə» çalışmırıq: o, tamamlanmış dəyişməz tip kimi nəzərdə tutulub.

Səhv №5: avtomatik generasiya olunan metodları görməməzlikdən gəlmək.
Əgər equals, hashCode və ya toString metodlarını override edirsinizsə, ehtiyatlı olun — onların kontraktını pozmayın, yoxsa kolleksiyalar və müqayisələr düzgün işləməyə bilər.

Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION