1. Klassik switch: keçmişin məhdudiyyətləri
Gəlin, pattern matching ortaya çıxmamışdan əvvəl Java-da switch necə idi, xatırlayaq. Açıq danışsaq, xeyli konservativ idi. Yalnız primitivlərlə (int, char və bir az sonra enum, String) işləyirdi, əgər müxtəlif obyekt tiplərini işləmək istəyirdinizsə — uzun if-else zəncirləri yazmalı olurdunuz.
Object obj = ...;
if (obj instanceof String) {
String s = (String) obj;
System.out.println("Sətir: " + s);
} else if (obj instanceof Integer) {
Integer i = (Integer) obj;
System.out.println("Ədəd: " + i);
} else if (obj == null) {
System.out.println("null!");
} else {
System.out.println("Başqa bir şey");
}
Rahatdır? O qədər də yox. Kod həcmli olur, asanlıqla səhv etmək olar və yeni tip əlavə olunsa — yenidən if-else zəncirini yenidən yazmaq lazım gəlir.
2. switch-də pattern matching: Java 17/21+-da inqilab
Java 17 (preview) və nəhayət Java 21+ pattern matching-i dəstəkləyən yeni switch versiyasını təqdim etdi. İndi switch təkcə primitivlərlə deyil, istənilən obyektlərlə, tiplərlə, hətta null ilə də işləyə bilir və əlavə şərtləri (guard-ifadələri) dəstəkləyir.
Yeni sintaksis: yığcamlıq və güc
switch-də sadə pattern matching nümunəsi:
Object obj = ...;
switch (obj) {
case String s -> System.out.println("Sətir: " + s);
case Integer i -> System.out.println("Ədəd: " + i);
case null -> System.out.println("null!");
default -> System.out.println("Başqa bir şey");
}
Burada nə baş verir?
- Əgər obj — sətirdirsə, s dəyişəni avtomatik olaraq String tipinə gətirilir.
- Əgər obj — tam ədəddirsə, i dəyişəni Integer olur.
- Əgər obj — null-dırsa, xüsusi budaq işləyəcək.
- Qalan hər şey — default.
Niyə bu rahatdır?
- Əl ilə tip çevirmə yoxdur: Java tip təhlükəsizliyinə özü nəzarət edir.
- Daha az kod: Artıq mötərizələr, kastlar və təkrarlamalar yoxdur.
- Daha təhlükəsizdir: Kompilyator mümkün variantları unutmadığınızdan əmin olur (xüsusilə sealed-siniflərlə, bu barədə sonra danışacağıq).
- Yeni tiplər əlavə etmək asandır: Sadəcə əlavə bir case budağı əlavə edin.
3. switch-də pattern matching: baza nümunələri
Nümunə 1: Müxtəlif tiplərin işlənməsi
Object obj = 42;
switch (obj) {
case String s -> System.out.println("Sətir: " + s);
case Integer i -> System.out.println("Ədəd: " + i);
case null -> System.out.println("Bu null");
default -> System.out.println("Naməlum tip");
}
Çıxış:
Ədəd: 42
Nümunə 2: Guard-ifadələrdən (when) istifadə
Bəzən təkcə tipi bilmək kifayət etmir — əlavə şərt də əlavə etmək istəyirsiniz.
Object obj = "Hello, world!";
switch (obj) {
case String s when s.length() > 10 -> System.out.println("Uzun sətir: " + s);
case String s -> System.out.println("Qısa sətir: " + s);
case Integer i when i > 0 -> System.out.println("Müsbət ədəd: " + i);
case Integer i -> System.out.println("Qeyri-müsbət ədəd: " + i);
default -> System.out.println("Başqa bir şey");
}
Çıxış:
Uzun sətir: Hello, world!
Nəzərə alın:
- when — bu, case üçün əlavə yoxlama olan guard-ifadədir.
- Əgər şərt ödənmirsə, növbəti case-lər yoxlanılır.
Nümunə 3: null-un işlənməsi
Object obj = null;
switch (obj) {
case null -> System.out.println("Bu null!");
default -> System.out.println("Null deyil");
}
Çıxış:
Bu null!
4. Klasslar və irsiyyət ilə switch-də pattern matching
Pattern matching switch ilə sinif ierarxiyalarında xüsusilə yaxşı işləyir.
sealed interface Shape permits Circle, Rectangle, Square {}
final class Circle implements Shape {
final double radius;
Circle(double radius) { this.radius = radius; }
}
final class Rectangle implements Shape {
final double width, height;
Rectangle(double width, double height) { this.width = width; this.height = height; }
}
final class Square implements Shape {
final double side;
Square(double side) { this.side = side; }
}
Shape shape = new Rectangle(2, 3);
String description = switch (shape) {
case Circle c -> "Radiusu " + c.radius + " olan dairə";
case Rectangle r -> "Düzbucaqlı " + r.width + "x" + r.height;
case Square s -> "Tərəfi " + s.side + " olan kvadrat";
};
System.out.println(description);
Çıxış:
Düzbucaqlı 2.0x3.0
Faydalı xüsusiyyət: Əgər siz sealed-siniflərdən istifadə edirsinizsə və onların bütün variantlarını işləyirsinizsə, default budağı tələb olunmur — kompilyator başa düşür ki, başqa variantlar ola bilməz!
5. record-siniflər və iç-içə patternlərlə switch-dən istifadə
switch-də pattern matching record-siniflərlə və iç-içə patternlərlə işləməyi dəstəkləyir (Java 21+-dən başlayaraq).
record Point(int x, int y) {}
record Line(Point start, Point end) {}
Object obj = new Line(new Point(1, 2), new Point(3, 4));
String result = switch (obj) {
case Line(Point(int x1, int y1), Point(int x2, int y2)) ->
"Xətt (" + x1 + "," + y1 + ") nöqtəsindən (" + x2 + "," + y2 + ") nöqtəsinədək";
case Point(int x, int y) -> "Nöqtə (" + x + "," + y + ")";
default -> "Naməlum obyekt";
};
System.out.println(result);
Çıxış:
Xətt (1,2)-dən (3,4)-dək
6. switch-də pattern matching-in xüsusiyyətləri və məhdudiyyətləri
Dəyişənlər yalnız case daxilində əlçatandır
Patterndə elan olunan dəyişən (məsələn, String s) yalnız uyğun case blokunun daxilində mövcuddur. Onun hüdudlarından kənarda əlçatan deyil.
switch (obj) {
case String s -> System.out.println(s); // burada s görünür
// System.out.println(s); // burada kompilyasiya xətası!
}
null-un işlənməsi
- Köhnə obyektlər üzərindəki switch-də null ötürmək cəhdləri NullPointerException-a səbəb olurdu.
- Yeni pattern matching switch-də null-u case null ilə açıq şəkildə işləmək mümkündür.
Guard-ifadələri (when)
Əlavə şərtlər (when) yalnız expression-üslublu switch-də (oxlu sintaksis ->) mövcuddur.
case String s when s.isEmpty() -> System.out.println("Boş sətir");
JDK və IDE tələbləri
- switch-də pattern matching — Java 17 (preview) və Java 21+ (stabil) xüsusiyyətidir.
- İşləməsi üçün JDK 21 və yeni imkanları dəstəkləyən IDE lazımdır (məsələn, IntelliJ IDEA 2023+).
7. Real tətbiqdə pattern matching switch-in tətbiqi
Tədris tətbiqinə baxaq — sadə tapşırıq-treker. Tutaq ki, abstrakt tapşırıq tipi və onun müxtəlif növləri var:
sealed interface Task permits SimpleTask, DeadlineTask, MeetingTask {}
final class SimpleTask implements Task {
final String description;
SimpleTask(String description) { this.description = description; }
}
final class DeadlineTask implements Task {
final String description;
final java.time.LocalDate deadline;
DeadlineTask(String description, java.time.LocalDate deadline) {
this.description = description;
this.deadline = deadline;
}
}
final class MeetingTask implements Task {
final String topic;
final java.time.LocalTime time;
MeetingTask(String topic, java.time.LocalTime time) {
this.topic = topic;
this.time = time;
}
}
Bütün məntiq bir yığcam switch-dədir:
Task task = new DeadlineTask("Layihəni təhvil vermək", java.time.LocalDate.of(2024, 7, 1));
String info = switch (task) {
case SimpleTask st -> "Adi tapşırıq: " + st.description;
case DeadlineTask dt -> "Müddətli tapşırıq: " + dt.description + ", " + dt.deadline + " tarixinədək";
case MeetingTask mt -> "Görüş: " + mt.topic + " saat " + mt.time;
};
System.out.println(info);
Çıxış:
Müddətli tapşırıq: Layihəni təhvil vermək, 2024-07-01 tarixinədək
8. switch-də pattern matching istifadə edərkən tipik səhvlər
Səhv №1: null-un işlənməsini unutmaq. Əgər siz case null əlavə etməmisinizsə və obj null ola bilərsə — MatchException (və ya köhnə switch-də NullPointerException) alacaqsınız. Mümkünsə, null-u həmişə açıq şəkildə işləyin.
Səhv №2: sealed-sinifin bütün varislərini nəzərə almamaq. Əgər siz sealed-sinifdən istifadə edir və switch-də bütün variantları işləmirsinizsə, kompilyator xəta verəcək və ya default budağını tələb edəcək. İerarxiyanı genişləndirərkən yeni case-ləri əlavə etməyi unutmayın.
Səhv №3: pattern dəyişəni case blokundan kənarda əlçatan deyil. Pattern-də elan olunan dəyişən yalnız oxlu blok daxilində mövcuddur. Onu bu blokdan kənarda istifadə etmək cəhdi kompilyasiya xətasına səbəb olacaq.
Səhv №4: yeni xüsusiyyətləri köhnə JDK və ya köhnə IDE-də istifadə etmək. switch-də pattern matching Java 21+ və sizin IDE-də uyğun dəstək tələb edir. Köhnə versiya istifadə etsəniz — kompilyasiya xətası və ya düzgün olmayan ipucları ala bilərsiniz.
Səhv №5: guard-ifadələri ilə çaşqınlıq. when-i köhnə bloklu switch-də istifadə etməyə çalışırsınız? Alınmayacaq. Guardlar yalnız oxlu sintaksis üçün əlçatandır ->.
Səhv №6: açıq ierarxiyalarla işləyərkən default-budağı unutmaq. Əgər sizin switch yalnız sealed-siniflərlə işləmirsə, mütləq default əlavə edin — əks halda bütün variantlar işlənməyəcək.
GO TO FULL VERSION