CodeGym /Kurslar /JAVA 25 SELF /Record Patterns (Java 21+): sintaksis, nümunələr

Record Patterns (Java 21+): sintaksis, nümunələr

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

1. Record siniflərinə dərindən baxış

record patterns-ə keçməzdən əvvəl, gəlin yaddaşı təzələyək: record sinfi nədir.

Record — bu, equals, hashCode, toString kimi metodları avtomatik yaradılan, həmçinin bütün komponentlər üçün getterləri avtomatik formalaşdırılan kompakt və dəyişməz (immutable) sinifdir. Record sinifləri Java 16-da ortaya çıxdı və əl ilə DTO-lar yazmaqdan yorulanlar üçün əsl hədiyyə oldu.

// Klassika: iki sahəli Point
record Point(int x, int y) {}

Obyektin yaradılması və sahələrə çıxış:

Point p = new Point(10, 20);
System.out.println(p.x()); // 10
System.out.println(p.y()); // 20
System.out.println(p);     // Point[x=10, y=20]

Record Patterns nə üçün lazımdır

Java 21-dək, əgər obyektin müəyyən bir record olduğunu yoxlamaq və onun sahələrini əldə etmək istəyirdinizsə, çoxlu əl işi kod yazmalı olurdunuz: tipi instanceof ilə yoxlamaq, cast etmək və getterləri çağırmaq.

Object obj = new Point(5, 7);
if (obj instanceof Point) {
    Point p = (Point) obj;
    int x = p.x();
    int y = p.y();
    System.out.println("x=" + x + ", y=" + y);
}

Əgər record mürəkkəb və ya yuvalanmışdırsa, kod tez bir zamanda çoxsaylı açma əməliyyatlarına çevrilir. Üstəlik, belə tanımanı switch-də istifadə etmək əvvəllər əlverişli deyildi.

Record patterns record siniflərinin dəyərlərini birbaşa pattern matching zamanı açmağa imkan verir: həm instanceof-da, həm də switch-də. Bu, kodu daha qısa, təhlükəsiz və anlaşıqlı edir.

2. Record patternlərin sintaksisi: ən sadə nümunə

record Point(int x, int y) {}

Object obj = new Point(10, 20);

if (obj instanceof Point(int x, int y)) {
    System.out.println("x=" + x + ", y=" + y);
}

Burada nə baş verir?

  • obj instanceof Point(int x, int y) — tipi yoxlayırıq və komponentləri birbaşa xy dəyişənlərinə açırıq.
  • xy dəyişənləri yalnız if blokunun daxilində əlçatandır.

Nəticə:

x=10, y=20

Diqqət: əgər obj Point deyilsə və ya null-dırsa, if bloku işləməyəcək və dəyişənlər elan olunmayacaq.

3. Record patterns switch-də: yığcamlıq və təhlükəsizlik

record Point(int x, int y) {}
record Circle(Point center, int radius) {}

Object shape = new Point(3, 4);

switch (shape) {
    case Point(int x, int y) -> System.out.println("Point: x=" + x + ", y=" + y);
    case Circle(Point center, int r) -> System.out.println("Circle with radius " + r);
    default -> System.out.println("Unknown shape!");
}
  • case Point(int x, int y)-də biz dərhal xy-ə çıxış əldə edirik.
  • case Circle(Point center, int r)-də centerr əlçatandır.

Nəticə:

Point: x=3, y=4

sealed ierarxiyaları ilə switch tam əhatəli olur: hansısa varianta emal etməyi unutsanız, kompilyator xəbərdar edəcək.

4. Yuvalanmış record patterns: iç-içə açma

record Point(int x, int y) {}
record Line(Point start, Point end) {}

Object obj = new Line(new Point(1, 2), new Point(3, 4));

if (obj instanceof Line(Point(int x1, int y1), Point(int x2, int y2))) {
    System.out.println("Line from (" + x1 + "," + y1 + ") to (" + x2 + "," + y2 + ")");
}

Nəticə:

Line from (1,2) to (3,4)

Ağaçlar, qraflar, mürəkkəb strukturlarla işləyirsiniz? Yuvalanmış patternlər sizin dostunuzdur.

5. Guard ifadələri (when) ilə record patterns

Object obj = new Point(0, 100);

if (obj instanceof Point(int x, int y) && x == 0) {
    System.out.println("Nöqtə Y oxu üzərindədir: y=" + y);
}

switch-də bu, when köməyi ilə edilir:

switch (obj) {
    case Point(int x, int y) when x == 0 -> System.out.println("Y oxunda: y=" + y);
    case Point(int x, int y) when y == 0 -> System.out.println("X oxunda: x=" + x);
    case Point(int x, int y) -> System.out.println("Adi nöqtə");
    default -> System.out.println("Nöqtə deyil");
}

6. Record patternlərin real tətbiqdə istifadəsi

Praktik nümunə götürək — həndəsi fiqurlar.

record Point(int x, int y) {}
record Circle(Point center, int radius) {}
record Rectangle(Point topLeft, int width, int height) {}
public static void printShapeInfo(Object shape) {
    switch (shape) {
        case Point(int x, int y) -> System.out.println("Point: (" + x + ", " + y + ")");
        case Circle(Point(int x, int y), int radius) ->
            System.out.println("Circle: center=(" + x + ", " + y + "), radius=" + radius);
        case Rectangle(Point(int x, int y), int width, int height) ->
            System.out.println("Rectangle: topLeft=(" + x + ", " + y + "), size=" + width + "x" + height);
        default -> System.out.println("Unknown shape");
    }
}

Çağırış nümunəsi:

printShapeInfo(new Rectangle(new Point(5, 10), 20, 30));

Nəticə:

Rectangle: topLeft=(5, 10), size=20x30

7. Record patternlərin istifadəsinin məhdudiyyətləri və incəlikləri

Yalnız record sinifləri üçün. Record patternlər yalnız həqiqətən record sinifləri olan obyektlərlə işləyir.

class NotARecord {
    int a, b;
    NotARecord(int a, int b) { this.a = a; this.b = b; }
}

// Səhv! Record deyil
// if (obj instanceof NotARecord(int a, int b)) { ... }

Komponentlərin say və tip üzrə uyğunluğu. Şablon record sinifinin komponentlərinə uyğun olmalıdır.

record Pair(int a, String b) {}

// Səhv: tiplər uyğun gəlmir
// if (obj instanceof Pair(String a, int b)) { ... }

Dəyişənlər yalnız blok daxilində əlçatandır. Pattern-də elan olunan adlar yalnız uyğunluq uğurlu olduğu konkret if və ya case blokunun daxilində görünür.

8. Yuvalanmış patternlər: ağac nümunəsi

sealed interface Expr permits NumberExpr, PlusExpr, MinusExpr {}

record NumberExpr(int value) implements Expr {}
record PlusExpr(Expr left, Expr right) implements Expr {}
record MinusExpr(Expr left, Expr right) implements Expr {}
int eval(Expr expr) {
    return switch (expr) {
        case NumberExpr(int value) -> value;
        case PlusExpr(Expr left, Expr right) -> eval(left) + eval(right);
        case MinusExpr(Expr left, Expr right) -> eval(left) - eval(right);
    };
}

İstifadə nümunəsi:

Expr e = new PlusExpr(new NumberExpr(7), new MinusExpr(new NumberExpr(10), new NumberExpr(3)));
System.out.println(eval(e)); // 7 + (10 - 3) = 14

Burada biz dərhal NumberExpr(int value), PlusExpr(Expr left, Expr right)MinusExpr(Expr left, Expr right) açırıq — kod daha yığcam və ifadəli olur.

9. Cədvəl: record patternlərlə və onlarsız pattern matching müqayisəsi

Usul Tip çevirmə əl ilə Record patternlərlə Pattern Matching
Tip yoxlaması
if (obj instanceof ...)
if (obj instanceof Point(int x, int y))
Tip çevirmə
(Point) obj
Lazım deyil
Sahələrə çıxış
p.x(), p.y()
x, y
Yuvalanmış açma Çox əl işi kod Yuvalanmış patternlər
switch-də istifadə Narahat/mümkün deyil Asan, yığcam

10. Record patternlərdən istifadə zamanı tipik səhvlər

Səhv №1: record olmayan sinfə record pattern tətbiq etməyə cəhd. Əgər adi sinif yazmısınızsa və onu record kimi “açmağa” çalışırsınızsa, kompilyator icazə verməyəcək. Record patternlər yalnız əsl record sinifləri ilə işləyir.

Səhv №2: komponentlərin sayı və ya tipinin uyğun gəlməməsi. Şablon record-un komponentlərinin imzasına tam uyğun olmalıdır. Məsələn, record Pair(int a, String b) üçün Pair(int x, int y) yazmaq olmaz.

Səhv №3: pattern dəyişənlərini blokdan kənarda istifadə etməyə cəhd. Şablonda elan edilən adlar yalnız müvafiq if/case daxilində əlçatandır. Blokdan kənarda belə dəyişənlər mövcud deyil.

Səhv №4: köhnə JDK versiyalarında record patternlərdən istifadə. Dəstək Java 21-də peyda olub. Java 17 və daha aşağıda sintaksis xətası alacaqsınız. JDK versiyasını və IDE-də dəstəyi yoxlayın.

Səhv №5: həddindən artıq dərin yuvalanmış patternlər. Yuvalama imkanları güclüdür, amma zərurət olmadıqda mürəkkəbləşdirməyin: həddindən artıq dərin struktur oxunaqlığı pisləşdirir və xəta riskini artırır.

1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Həndəsə redaktoru: nöqtələrin vəziyyətinin təsviri 📍
Həndəsə redaktoru: nöqtələrin vəziyyətinin təsviri 📍
1
Tapşırıq
JAVA 25 SELF, səviyyə, dərs
Bağlanıb
Kalkulyatorun beyin mərkəzi: mürəkkəb ifadələrin qiymətləndirilməsi 🧠➕➖
Kalkulyatorun beyin mərkəzi: mürəkkəb ifadələrin qiymətləndirilməsi 🧠➕➖
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION