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 x və y dəyişənlərinə açırıq.
- x və y 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 x və y-ə çıxış əldə edirik.
- case Circle(Point center, int r)-də center və r ə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) və 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ı | |
|
| Tip çevirmə | |
Lazım deyil |
| Sahələrə çıxış | |
|
| 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.
GO TO FULL VERSION