Java 14 (Mart 2020) — Detaylı Sürüm Analizi
> Bu doküman Java 14 sürümüyle gelen önemli dil ve platform özelliklerini Türkçe olarak, > "nedir / neden geldi / ne işe yarar / nerede kolaylık sağlar / eski vs yeni / gerçek hayat" > başlıklarıyla derinlemesine anla…
Java 14 (Mart 2020) — Detaylı Sürüm Analizi
Bu doküman Java 14 sürümüyle gelen önemli dil ve platform özelliklerini Türkçe olarak, "nedir / neden geldi / ne işe yarar / nerede kolaylık sağlar / eski vs yeni / gerçek hayat" başlıklarıyla derinlemesine anlatır. Her özellik için çalışan
.javaörnek dosyalarına referans verilmiştir.
Sürüm Bilgisi
| Bilgi | Değer |
|---|---|
| Sürüm | Java SE 14 / JDK 14 |
| Çıkış Tarihi | 17 Mart 2020 |
| Tür | Feature Release (6 aylık döngü) |
| LTS mi? | Hayır (LTS değil; bir sonraki LTS 17'dir) |
| Önceki sürüm | Java 13 (Eylül 2019) |
| Sonraki sürüm | Java 15 (Eylül 2020) |
Java 14'ün Tarihsel Önemi
Java 14, dil seviyesinde "modern Java"nın temellerinin atıldığı sürümlerden biridir. Üç büyük olay aynı anda gerçekleşti:
- Switch Expressions KALICI oldu — 12 ve 13'te preview olan özellik artık standart dilin parçası.
- Records ilk kez preview olarak geldi — boilerplate'i yok eden veri taşıyıcı sınıflar.
- Pattern Matching for
instanceofilk kez preview olarak geldi —instanceof+ cast tek adımda.
Ayrıca Helpful NullPointerExceptions özelliği geldi ve debugging'i kökten değiştirdi.
Preview → Kalıcı Evrimi (ÇOK ÖNEMLİ)
Java, yeni dil özelliklerini önce "preview" (önizleme) olarak sunar; topluluk geri bildirimiyle olgunlaştırıp sonraki sürümlerde kalıcı (standart) hale getirir. Java 14'teki üç dil özelliğinin yaşam döngüsü şöyledir:
| Özellik | Preview Başlangıcı | KALICI Olduğu Sürüm | Java 14'teki Durumu |
|---|---|---|---|
| Switch Expressions | Java 12 (preview), Java 13 (2. preview) | Java 14 | KALICI — --enable-preview artık GEREKMEZ |
| Records | Java 14 (1. preview) | Java 16 | Preview — --enable-preview --release 14 gerekir |
| Pattern Matching for instanceof | Java 14 (1. preview) | Java 16 | Preview — --enable-preview --release 14 gerekir |
| Text Blocks (bağlam) | Java 13 (preview) | Java 15 | 2. preview (14'te hâlâ preview) |
Preview özelliği nasıl derlenir/çalıştırılır?
javac --enable-preview --release 14 RecordsPreview.java java --enable-preview RecordsPreviewBu repodaki örnekler Java 16+ (Records ve pattern matching kalıcı olduktan sonra) ile
--enable-previewOLMADAN da derlenir. Yorumlarda her dosyada Java 14 preview durumu net belirtilmiştir.
Kapsanan Özellikler ve Örnek Dosyalar
| # | Özellik | Durum | Örnek Dosya |
|---|---|---|---|
| 1 | Switch Expressions | KALICI | SwitchExpressionsKalici.java |
| 2 | Records | Preview | RecordsPreview.java |
| 3 | Pattern Matching for instanceof | Preview | PatternMatchingInstanceof.java |
| 4 | Helpful NullPointerExceptions | Standart (varsayılan açık) | HelpfulNullPointer.java |
| 5 | Foreign-Memory Access API | Incubator | (yalnızca bu README'de açıklanmıştır) |
1) Switch Expressions (JEP 361) — Artık KALICI
NEDİR
Switch'in bir ifade (expression) olarak değer döndürebilmesidir. Klasik switch bir
"deyim" (statement) idi; akış kontrolü yapardı ama doğrudan bir değer üretmezdi. Switch
Expressions ile switch artık bir değer döndürür ve onu bir değişkene atayabilirsiniz.
NEDEN GELDİ (Hangi problemi çözüyor)
Klasik switch üç büyük dert çıkarıyordu:
breakunutma hatası (fall-through): Hercasesonundabreakyazmazsanız bir sonraki case'e "düşer" (fall-through) ve sessizce yanlış davranış oluşur — en sık görülen hatalardan biriydi.- Değer döndürememe: Bir değişkene değer atamak için switch'ten ÖNCE değişkeni tanımlayıp her case içinde elle set etmek gerekiyordu.
- Sözdizimi gürültüsü: Çok satırlı, tekrarlı
case ...: ...; break;blokları.
NE İŞE YARAR
->(ok) söz dizimiyle fall-through tamamen ortadan kalkar (otomatikbreak).switchdoğrudan bir değer döndürür; sonucu değişkene atayabilirsiniz.- Çoklu case tek satırda virgülle:
case PAZARTESI, SALI, CARSAMBA -> .... - Çok satırlı blok gerektiğinde
yieldile değer döndürülür.
NEREDE KOLAYLIK SAĞLAR
Enum'lara göre dallanan iş kuralları, durum makineleri (state machine), HTTP durum kodu eşlemeleri, gün/ay hesaplamaları, fiyat/indirim kuralları — yani "girdiye göre bir değer üret" senaryolarının tamamında.
ESKİ vs YENİ
// ESKİ (Java 11 ve öncesi) — break gerektirir, fall-through riski var int gunSayisi; switch (ay) { case OCAK: case MART: case MAYIS: gunSayisi = 31; break; // unutursan hata! case SUBAT: gunSayisi = 28; break; default: gunSayisi = 30; } // YENİ (Java 14 KALICI) — değer döndürür, break yok, fall-through yok int gunSayisi = switch (ay) { case OCAK, MART, MAYIS -> 31; case SUBAT -> 28; default -> 30; };
GERÇEK HAYAT ÖRNEĞİ
Bir e-ticaret sisteminde müşteri segmentine göre indirim oranı belirleme; bir bankacılık
uygulamasında işlem tipine göre komisyon hesaplama. Detaylı çalışan örnek:
SwitchExpressionsKalici.java
Avantaj / Dezavantaj / Risk
- Avantaj: Daha az kod, fall-through hatası imkânsız, exhaustiveness (enum'da tüm değerleri kapsama) kontrolü derleyici tarafından zorlanır.
- Dezavantaj: Çok eski Java'ya alışkın ekiplerde okuma alışkanlığı değişimi gerekir.
- Risk: Yok denecek kadar az; Java 14'ten itibaren tamamen standart.
2) Records (JEP 359) — Preview
NEDİR
record, yalnızca veri taşımak için tasarlanmış, değişmez (immutable) ve özlü (concise)
bir sınıf türüdür. Tek satırda tanımladığınız bir record, sizin için otomatik olarak şunları
üretir: private final alanlar, tüm alanları alan canonical constructor, her alan için
accessor (getter) metotlar, equals(), hashCode() ve toString().
public record Nokta(int x, int y) { } // Hepsi bu kadar!
NEDEN GELDİ (Hangi problemi çözüyor)
Java'da basit bir veri sınıfı (DTO/POJO) yazmak ACI VERİCİ derecede tekrarlıydı. Sadece x ve
y taşıyan bir sınıf için ~50 satır boilerplate yazmak gerekiyordu: constructor, getter'lar,
equals, hashCode, toString. Bu kod hem yazması sıkıcı hem bakımı tehlikeliydi — yeni bir
alan eklediğinizde equals/hashCode/toString'i güncellemeyi unutmak çok kolaydı ve bu da
sinsi hatalara yol açıyordu.
NE İŞE YARAR
- Tek satırda tam bir veri sınıfı — boilerplate yok.
- Otomatik immutability (tüm alanlar
final). - Otomatik, değer tabanlı
equals/hashCode(iki record aynı alan değerlerine sahipse eşittir). - Okunabilir otomatik
toString(Nokta[x=3, y=4]). - Compact constructor ile tek yerde validasyon.
NEREDE KOLAYLIK SAĞLAR
DTO'lar (Data Transfer Object), API request/response modelleri, değer nesneleri (value object),
metottan birden fazla değer döndürme (tuple yerine), map anahtarları (otomatik equals/hashCode
sayesinde), event/mesaj payload'ları.
ESKİ vs YENİ
// ESKİ — basit bir 2D nokta için ~30+ satır boilerplate public final class NoktaEski { private final int x; private final int y; public NoktaEski(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) { /* ... */ } @Override public int hashCode() { /* ... */ } @Override public String toString() { /* ... */ } } // YENİ — aynı işi yapan record public record Nokta(int x, int y) { }
GERÇEK HAYAT ÖRNEĞİ
Bir REST API'de KullaniciDTO, ApiResponse<T>, koordinat/para birimi gibi value object'ler.
Compact constructor ile gelen verinin doğrulanması. Derinlemesine çalışan örnek (eski ~50 satır
POJO vs tek satır record karşılaştırmasıyla): RecordsPreview.java
Avantaj / Dezavantaj / Risk
- Avantaj: Devasa boilerplate azalması, immutability, doğru
equals/hashCodegarantisi. - Dezavantaj: Record alanları zorunlu olarak
final'dır; "mutable" varlık (entity) modeli için uygun değildir. Kalıtım desteklemez (record'lar implicitlyfinal'dır, başka sınıftan extend edemez). - Risk: Java 14'te preview —
--enable-preview --release 14gerekir; API/sözdizimi ileride değişebilirdi. Java 16'da KALICI oldu, artık risksizdir.
3) Pattern Matching for instanceof (JEP 305) — Preview
NEDİR
instanceof kontrolü ile birlikte, tip uyuyorsa nesneyi otomatik olarak yeni bir değişkene
bağlayan (bind) bir özellik. Ayrıca elle cast yapma ihtiyacını ortadan kaldırır.
if (obj instanceof String s) { // 's' burada zaten String tipinde; cast'e gerek yok System.out.println(s.length()); }
NEDEN GELDİ (Hangi problemi çözüyor)
instanceof sonrası neredeyse her zaman aynı tipe cast yapılırdı. Bu üç satırlık kalıp
(instanceof kontrolü → değişken tanımı → cast) hem tekrarlıydı hem de cast'i yanlış tipe
yapma riski taşıyordu (gerçi derleyici çoğunu yakalar ama yine de gürültü).
NE İŞE YARAR
- Tip kontrolü ve cast tek adımda birleşir; "binding variable" otomatik oluşur.
- Kod daha kısa, daha güvenli, daha okunaklı olur.
- Binding değişkeni, koşulun doğru olduğu kapsamda (flow scoping) kullanılabilir.
NEREDE KOLAYLIK SAĞLAR
equals() override etme, generic/Object parametre işleme, JSON/Object parse, ziyaretçi
(visitor) benzeri tip-temelli dallanmalar, polymorphic veri işleme.
ESKİ vs YENİ
// ESKİ — kontrol + tanım + cast (3 satır, gereksiz cast) if (obj instanceof String) { String s = (String) obj; System.out.println(s.length()); } // YENİ — tek satır, otomatik bağlama if (obj instanceof String s) { System.out.println(s.length()); }
GERÇEK HAYAT ÖRNEĞİ
Farklı tipte nesneleri işleyen bir metot ve klasik equals override'ı. Detaylı çalışan örnek:
PatternMatchingInstanceof.java
Avantaj / Dezavantaj / Risk
- Avantaj: Daha az kod, cast hatalarının elenmesi, flow scoping ile temiz kapsam.
- Dezavantaj: Çok karmaşık koşullarda binding değişkeninin kapsamını takip etmek zihinsel yük getirebilir.
- Risk: Java 14'te preview. Java 16'da KALICI oldu.
4) Helpful NullPointerExceptions (JEP 358) — Standart
NEDİR
NullPointerException (NPE) mesajlarının, tam olarak hangi değişkenin/metodun null olduğunu açıkça söylemesi. Eskiden NPE sadece satır numarası verirdi; o satırda birden çok null adayı varsa hangisinin patladığını tahmin etmeniz gerekirdi.
NEDEN GELDİ (Hangi problemi çözüyor)
a.getB().getC().getD() gibi zincirleme çağrılarda eski NPE şöyle derdi:
Exception in thread "main" java.lang.NullPointerException at com.ornek.App.main(App.java:42)
Bu satırda a, getB()'nin sonucu, getC()'nin sonucu — hangisi null? Belli değil! Debugging
saatler alabiliyordu.
NE İŞE YARAR
Java 14'ten itibaren NPE mesajı tam olarak şunu söyler:
Cannot invoke "Sehir.getPostaKodu()" because the return value of "Adres.getSehir()" is null
Yani: "Adres.getSehir() null döndürdüğü için Sehir.getPostaKodu() çağrılamadı." — Hangi
parçanın null olduğu kristal netliğinde.
NEREDE KOLAYLIK SAĞLAR
İç içe nesne grafikleri (object graph), DTO/entity zincirleri, üretim (production) loglarındaki NPE'lerin teşhisi, eğitim/öğrenme. Debugger açmadan logdan doğrudan kök nedeni görmek.
Aktivasyon Notu
- Java 14'te flag:
-XX:+ShowCodeDetailsInExceptionMessages. - Java 15'ten itibaren bu davranış VARSAYILAN olarak AÇIKTIR (flag'e gerek yok).
- Java 14'te varsayılan deneysel/açıktı; kapatmak için
-XX:-ShowCodeDetailsInExceptionMessages.
ESKİ vs YENİ
ESKİ (Java 13): java.lang.NullPointerException at App.main(App.java:42) YENİ (Java 14+): java.lang.NullPointerException: Cannot invoke "Sehir.getPostaKodu()" because the return value of "Adres.getSehir()" is null at App.main(App.java:42)
GERÇEK HAYAT ÖRNEĞİ
Kullanıcı → Adres → Şehir → PostaKodu zinciri; bilerek null bırakılan bir halka ve yakalanan
NPE mesajının yazdırılması. Detaylı çalışan örnek: HelpfulNullPointer.java
Avantaj / Dezavantaj / Risk
- Avantaj: Debugging süresinde dramatik kısalma, daha anlaşılır production logları.
- Dezavantaj: Çok nadir durumlarda mesaj oluşturmak değişken adlarını bytecode'dan okuyabilir (varsayılan kapalıyken gizlilik kaygısı vardı; bu yüzden 14'te opsiyoneldi, 15'te açıldı).
- Risk: Yok; tamamen geriye uyumlu.
5) Foreign-Memory Access API (JEP 370) — Incubator (yalnızca açıklama)
NEDİR
Java programlarının, JVM yığını (heap) DIŞINDAKİ bellekteki (off-heap / native memory) verilere
güvenli ve verimli erişebilmesi için tasarlanmış yeni bir API'dir. MemorySegment,
MemoryAddress ve MemoryLayout gibi soyutlamalar sunar.
NEDEN GELDİ (Hangi problemi çözüyor)
Java tarihinde off-heap belleğe erişmenin iki yolu vardı ve ikisi de sorunluydu:
ByteBuffer(java.nio): Boyut sınırlı (max ~2GB / Integer.MAX_VALUE), serbest bırakma (deallocation) zamanlaması belirsiz (GC'ye bağlı).sun.misc.Unsafe: Resmi olmayan, tehlikeli, desteklenmeyen, kaldırılması planlanan bir iç API. Yanlış kullanım JVM'i çökertebiliyordu.
Foreign-Memory Access API, bu iki kötü seçeneğin yerine güvenli, deterministik ve performanslı bir alternatif getirir.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR
- Büyük native bellek bloklarıyla çalışma (büyük veri, bellek-eşlemeli dosyalar, native kütüphane tamponları).
- Deterministik bellek yönetimi (ne zaman serbest bırakılacağı kontrol edilebilir).
- Yüksek performanslı I/O, native interoperability (sonraki sürümlerde Foreign Function & Memory API — Project Panama'nın bir parçası — olarak olgunlaştı).
Durumu
Java 14'te incubator modülüdür (jdk.incubator.foreign). Incubator, preview'dan daha erken
bir olgunluk seviyesidir; deneme amaçlıdır ve --add-modules jdk.incubator.foreign ile
etkinleştirilir. Project Panama kapsamında Java 21'de Foreign Function & Memory API olarak
kalıcılaştı (JEP 442/454). Bu repodaki örneklerde incubator modülü için çalışan kod verilmemiştir
(amaca uygun olarak yalnızca kavramsal açıklama).
Java 13'ten 14'e Geçişte Ne Değişti? (Özet)
| Konu | Java 13 | Java 14 |
|---|---|---|
| Switch Expressions | Preview (2.) | KALICI (artık standart) |
| Records | Yok | Preview (1.) |
| Pattern Matching for instanceof | Yok | Preview (1.) |
| Helpful NPE | Yok | Var (-XX:+ShowCodeDetailsInExceptionMessages) |
| Text Blocks | Preview (1.) | Preview (2.) (15'te kalıcı) |
| Foreign-Memory Access | Yok | Incubator |
| GC | Mevcut | ZGC ve Shenandoah olgunlaştı; CMS GC kaldırıldı (JEP 363) |
Geçişte Dikkat Edilecekler
- CMS Garbage Collector kaldırıldı (JEP 363):
-XX:+UseConcMarkSweepGCkullanan eski yapılandırmalar artık çalışmaz; G1 (varsayılan) veya ZGC'ye geçilmelidir. - Switch Expressions kullanıyorsanız
--enable-previewbayraklarını kaldırabilirsiniz (14'te kalıcı oldu). - Records ve pattern matching denemek için
--enable-preview --release 14gerekir.
Bu Repoyu Derleme / Çalıştırma
Bu repodaki örnekler Java 16+ (Records ve pattern matching'in kalıcılaştığı sürüm) ile
--enable-preview OLMADAN derlenir. Java 21 önerilir:
cd /Users/miracguntogar/Desktop/test/Java-Versiyon-Analizi/07-Java-14/ # Tek tek derleme + çalıştırma (Java 16+): javac SwitchExpressionsKalici.java && java SwitchExpressionsKalici javac RecordsPreview.java && java RecordsPreview javac PatternMatchingInstanceof.java && java PatternMatchingInstanceof javac HelpfulNullPointer.java && java HelpfulNullPointer
Java 14'te (tarihsel doğruluk için) preview özelliklerini derlemek isterseniz:
javac --enable-preview --release 14 RecordsPreview.java java --enable-preview RecordsPreview
Helpful NPE Java 14'te flag gerektirir:
java -XX:+ShowCodeDetailsInExceptionMessages ...Java 15+ ile varsayılan açıktır.
▶ Kod Örnekleri(4)
HelpfulNullPointer
çalıştırılabilir1/*
2 * =============================================================================
3 * Java 14 - HELPFUL NULLPOINTEREXCEPTIONS
4 * JEP 358: Helpful NullPointerExceptions
5 * =============================================================================
6 *
7 * DURUM:
8 * - Java 14: Geldi. Etkinlestirme bayragi:
9 * java -XX:+ShowCodeDetailsInExceptionMessages HelpfulNullPointer
10 * - Java 15 ve sonrasi: VARSAYILAN olarak ACIK (bayraga gerek YOK).
11 *
12 * Bu ornek Java 15+ (ornegin Java 21) ile dogrudan calistiginda yardimci
13 * NPE mesajini gosterir. Java 14'te yukaridaki bayrak gerekir.
14 *
15 * PROBLEM:
16 * a.getB().getC().getD() gibi ZINCIRLEME erisimlerde, eski NPE mesaji
17 * sadece satir numarasi verirdi. O satirda birden cok "null adayi" varsa
18 * HANGISININ null oldugunu tahmin etmeniz gerekirdi -> saatlerce debug.
19 *
20 * COZUM:
21 * Java 14+ NPE mesaji TAM OLARAK hangi parcanin null oldugunu soyler:
22 * 'Cannot invoke "Sehir.getPostaKodu()" because the return value of
23 * "Adres.getSehir()" is null'
24 * =============================================================================
25 */
26public class HelpfulNullPointer {
27
28 public static void main(String[] args) {
29 System.out.println("=== Java 14: Helpful NullPointerExceptions ===\n");
30 System.out.println("(Java 14'te calistirmak icin: "
31 + "java -XX:+ShowCodeDetailsInExceptionMessages HelpfulNullPointer)");
32 System.out.println("(Java 15+ varsayilan ACIK; ek bayrak gerekmez)\n");
33
34 // -------------------------------------------------------------------
35 // GERCEK HAYAT: Ic ice nesne grafigi
36 // Kullanici -> Adres -> Sehir -> postaKodu
37 // Bilerek bir halkayi null birakiyoruz.
38 // -------------------------------------------------------------------
39
40 // SENARYO 1: Sehir.getPostaKodu() null degil ama Adres.getSehir() null.
41 // Yani zincir ORTASINDA bir halka kopuk.
42 System.out.println("--- SENARYO 1: Adres var, ama Sehir null ---");
43 Kullanici k1 = new Kullanici(
44 "Ayse",
45 new Adres("Bagdat Cad. No:10", /* sehir = */ null) // <-- sehir NULL!
46 );
47 try {
48 // Zincirleme erisim: k1.adres().sehir().postaKodu()
49 String postaKodu = k1.adres().sehir().postaKodu();
50 System.out.println("Posta kodu: " + postaKodu);
51 } catch (NullPointerException e) {
52 // Java 14+ ile mesaj TAM olarak hangi parcanin null oldugunu soyler.
53 System.out.println("NPE yakalandi -> " + e.getMessage());
54 System.out.println(" (Eski Java'da burada SADECE satir numarasi olurdu,"
55 + " mesaj BOS olurdu.)");
56 }
57 System.out.println();
58
59 // SENARYO 2: Kullanicinin adresi tamamen null.
60 // Zincirin ILK halkasi kopuk.
61 System.out.println("--- SENARYO 2: Kullanicinin adresi null ---");
62 Kullanici k2 = new Kullanici("Mehmet", /* adres = */ null); // <-- adres NULL!
63 try {
64 String postaKodu = k2.adres().sehir().postaKodu();
65 System.out.println("Posta kodu: " + postaKodu);
66 } catch (NullPointerException e) {
67 System.out.println("NPE yakalandi -> " + e.getMessage());
68 }
69 System.out.println();
70
71 // SENARYO 3: Tum zincir saglam -> hata yok.
72 System.out.println("--- SENARYO 3: Zincir saglam (hata yok) ---");
73 Kullanici k3 = new Kullanici(
74 "Zeynep",
75 new Adres("Ataturk Bulv. No:5", new Sehir("Ankara", "06000"))
76 );
77 String postaKodu = k3.adres().sehir().postaKodu();
78 System.out.println("Posta kodu: " + postaKodu);
79 System.out.println();
80
81 // -------------------------------------------------------------------
82 // BONUS: Dizi/alan erisiminde de yardimci mesaj
83 // -------------------------------------------------------------------
84 System.out.println("--- BONUS: Dizi elemani null ---");
85 Sehir[] sehirler = new Sehir[3]; // tum elemanlar null
86 try {
87 String ad = sehirler[1].ad(); // sehirler[1] null
88 System.out.println(ad);
89 } catch (NullPointerException e) {
90 System.out.println("NPE yakalandi -> " + e.getMessage());
91 }
92
93 System.out.println("\nSONUC: Helpful NPE, ZINCIRLEME erisimlerde hangi"
94 + " halkanin koptugunu");
95 System.out.println(" dogrudan soyleyerek debugging suresini dramatik"
96 + " olarak kisaltir.");
97 }
98
99 // =========================================================================
100 // Ic ice nesne grafigi modeli (gercek hayatta DTO/entity zinciri gibi)
101 // =========================================================================
102 static final class Kullanici {
103 private final String ad;
104 private final Adres adres;
105 Kullanici(String ad, Adres adres) { this.ad = ad; this.adres = adres; }
106 String ad() { return ad; }
107 Adres adres() { return adres; }
108 }
109
110 static final class Adres {
111 private final String sokak;
112 private final Sehir sehir;
113 Adres(String sokak, Sehir sehir) { this.sokak = sokak; this.sehir = sehir; }
114 String sokak() { return sokak; }
115 Sehir sehir() { return sehir; }
116 }
117
118 static final class Sehir {
119 private final String ad;
120 private final String postaKodu;
121 Sehir(String ad, String postaKodu) { this.ad = ad; this.postaKodu = postaKodu; }
122 String ad() { return ad; }
123 String postaKodu() { return postaKodu; }
124 }
125}PatternMatchingInstanceof
çalıştırılabilir1/*
2 * =============================================================================
3 * Java 14 - PATTERN MATCHING FOR instanceof (PREVIEW)
4 * JEP 305: Pattern Matching for instanceof (Preview)
5 * =============================================================================
6 *
7 * PREVIEW DURUMU (cok onemli):
8 * - Java 14: instanceof pattern matching ILK preview olarak geldi.
9 * Derlemek icin: javac --enable-preview --release 14 PatternMatchingInstanceof.java
10 * Calistirmak: java --enable-preview PatternMatchingInstanceof
11 * - Java 15: 2. preview.
12 * - Java 16: ARTIK KALICI! "--enable-preview" gerekmez.
13 *
14 * Bu dosya Java 16+ (ornegin Java 21) ile preview bayragi OLMADAN derlenir.
15 *
16 * ANA FIKIR:
17 * Klasik kalip: if (obj instanceof String) { String s = (String) obj; ... }
18 * Yeni kalip: if (obj instanceof String s) { ... }
19 * -> Tip kontrolu + cast + degisken tanimi TEK ADIMDA birlesir.
20 * -> "s" otomatik olarak String tipinde baglanir (binding variable).
21 * =============================================================================
22 */
23public class PatternMatchingInstanceof {
24
25 public static void main(String[] args) {
26 System.out.println("=== Java 14: Pattern Matching for instanceof (Preview) ===\n");
27
28 // -------------------------------------------------------------------
29 // 1) ESKI vs YENI - aciklayici metin uretme
30 // -------------------------------------------------------------------
31 Object[] nesneler = {
32 "Merhaba Dunya",
33 42,
34 3.14,
35 java.util.List.of("a", "b", "c"),
36 true
37 };
38
39 System.out.println("--- ESKI yol (gereksiz cast ile) ---");
40 for (Object o : nesneler) {
41 System.out.println(" " + aciklaEski(o));
42 }
43
44 System.out.println("\n--- YENI yol (pattern matching ile) ---");
45 for (Object o : nesneler) {
46 System.out.println(" " + aciklaYeni(o));
47 }
48 System.out.println();
49
50 // -------------------------------------------------------------------
51 // 2) GERCEK HAYAT: equals() override - en sik kullanim alani
52 // -------------------------------------------------------------------
53 System.out.println("--- Gercek Hayat: equals() override ---");
54 Urun u1 = new Urun("Klavye", 750);
55 Urun u2 = new Urun("Klavye", 750);
56 Urun u3 = new Urun("Mouse", 300);
57 System.out.println("u1.equals(u2) : " + u1.equals(u2)); // true
58 System.out.println("u1.equals(u3) : " + u1.equals(u3)); // false
59 System.out.println("u1.equals(\"x\"): " + u1.equals("x")); // false
60 System.out.println();
61
62 // -------------------------------------------------------------------
63 // 3) GERCEK HAYAT: Object iceren bir "JSON benzeri" deger isleme
64 // -------------------------------------------------------------------
65 System.out.println("--- Gercek Hayat: JSON benzeri deger formatlama ---");
66 System.out.println(" " + jsonDeger("isim"));
67 System.out.println(" " + jsonDeger(2026));
68 System.out.println(" " + jsonDeger(true));
69 System.out.println(" " + jsonDeger(null));
70 System.out.println(" " + jsonDeger(99.5));
71 }
72
73 /**
74 * ESKI YOL: instanceof kontrolu + ayri cast + degisken tanimi.
75 * Her tip icin 3 satirlik tekrar; cast gurultusu.
76 */
77 static String aciklaEski(Object o) {
78 if (o instanceof String) {
79 String s = (String) o; // gereksiz, tekrarli cast
80 return "Metin uzunlugu: " + s.length();
81 } else if (o instanceof Integer) {
82 Integer i = (Integer) o;
83 return "Tam sayi karesi: " + (i * i);
84 } else if (o instanceof Double) {
85 Double d = (Double) o;
86 return "Ondalik yuvarlanmis: " + Math.round(d);
87 } else if (o instanceof java.util.List) {
88 java.util.List<?> list = (java.util.List<?>) o;
89 return "Liste boyutu: " + list.size();
90 }
91 return "Bilinmeyen tip: " + o;
92 }
93
94 /**
95 * YENI YOL: pattern matching - tip kontrolu ve binding tek adimda.
96 * Binding degiskeni (s, i, d, list) dogrudan kullanilabilir; cast YOK.
97 */
98 static String aciklaYeni(Object o) {
99 if (o instanceof String s) { // s -> String
100 return "Metin uzunlugu: " + s.length();
101 } else if (o instanceof Integer i) { // i -> Integer
102 return "Tam sayi karesi: " + (i * i);
103 } else if (o instanceof Double d) { // d -> Double
104 return "Ondalik yuvarlanmis: " + Math.round(d);
105 } else if (o instanceof java.util.List<?> list) { // list -> List
106 return "Liste boyutu: " + list.size();
107 }
108 return "Bilinmeyen tip: " + o;
109 }
110
111 /**
112 * JSON benzeri deger formatlama. Pattern matching ile tip-temelli
113 * dallanmanin ne kadar temiz oldugunu gosterir.
114 */
115 static String jsonDeger(Object o) {
116 if (o == null) {
117 return "null";
118 } else if (o instanceof String s) {
119 return "\"" + s + "\""; // metinler tirnak icinde
120 } else if (o instanceof Boolean b) {
121 return b ? "true" : "false";
122 } else if (o instanceof Number n) {
123 return n.toString(); // sayilar tirnaksiz
124 }
125 return "\"" + o + "\"";
126 }
127
128 // =========================================================================
129 // GERCEK HAYAT: equals() override - pattern matching'in klasik kullanimi
130 // Tek "&&" kosulunda hem tip kontrolu hem binding hem karsilastirma.
131 // =========================================================================
132 static final class Urun {
133 private final String ad;
134 private final int fiyat;
135
136 Urun(String ad, int fiyat) {
137 this.ad = ad;
138 this.fiyat = fiyat;
139 }
140
141 @Override
142 public boolean equals(Object o) {
143 // ESKI: if (!(o instanceof Urun)) return false; Urun u = (Urun) o; ...
144 // YENI: tek satirda kontrol + binding + flow scoping.
145 // "&&" sayesinde 'u', sadece instanceof TRUE iken erisilebilir
146 // (flow scoping); bu da kodu hem kisaltir hem guvenli kilar.
147 return o instanceof Urun u
148 && fiyat == u.fiyat
149 && java.util.Objects.equals(ad, u.ad);
150 }
151
152 @Override
153 public int hashCode() {
154 return java.util.Objects.hash(ad, fiyat);
155 }
156
157 @Override
158 public String toString() {
159 return "Urun{ad='" + ad + "', fiyat=" + fiyat + "}";
160 }
161 }
162}RecordsPreview
çalıştırılabilir1/*
2 * =============================================================================
3 * Java 14 - RECORDS (PREVIEW)
4 * JEP 359: Records (Preview)
5 * =============================================================================
6 *
7 * PREVIEW DURUMU (cok onemli):
8 * - Java 14: Records ILK preview olarak geldi.
9 * Derlemek icin: javac --enable-preview --release 14 RecordsPreview.java
10 * Calistirmak: java --enable-preview RecordsPreview
11 * - Java 15: 2. preview.
12 * - Java 16: ARTIK KALICI! "--enable-preview" gerekmez.
13 *
14 * Bu dosya Java 16+ (ornegin Java 21) ile preview bayragi OLMADAN derlenir.
15 *
16 * ANA FIKIR:
17 * "record", yalnizca VERI tasimak icin tasarlanmis, degismez (immutable),
18 * ozlu bir siniftir. Tek satirda tanimladiginiz record sizin yerinize sunlari
19 * OTOMATIK uretir:
20 * - private final alanlar
21 * - tum alanlari alan canonical constructor
22 * - her alan icin accessor (getter) metot: x(), y(), ad() ...
23 * - equals(), hashCode(), toString()
24 * =============================================================================
25 */
26import java.util.List;
27import java.util.Map;
28import java.util.Objects;
29
30public class RecordsPreview {
31
32 public static void main(String[] args) {
33 System.out.println("=== Java 14: Records (Preview) ===\n");
34
35 // -------------------------------------------------------------------
36 // BOLUM 1: ESKI vs YENI -- ayni 2D nokta, ayni davranis
37 // -------------------------------------------------------------------
38 System.out.println("--- BOLUM 1: ~50 satir POJO vs 1 satir record ---");
39
40 // ESKI: asagidaki NoktaEski sinifi ~50 satir boilerplate icerir.
41 NoktaEski eski1 = new NoktaEski(3, 4);
42 NoktaEski eski2 = new NoktaEski(3, 4);
43 System.out.println("ESKI POJO toString : " + eski1);
44 System.out.println("ESKI POJO equals : " + eski1.equals(eski2));
45 System.out.println("ESKI POJO getX : " + eski1.getX());
46
47 // YENI: ayni isi yapan record TEK SATIR (asagida Nokta tanimi).
48 Nokta yeni1 = new Nokta(3, 4);
49 Nokta yeni2 = new Nokta(3, 4);
50 System.out.println("YENI record toString: " + yeni1); // Nokta[x=3, y=4]
51 System.out.println("YENI record equals : " + yeni1.equals(yeni2)); // true
52 System.out.println("YENI record getter : " + yeni1.x()); // accessor: x()
53 System.out.println("YENI record hashCode esit mi: "
54 + (yeni1.hashCode() == yeni2.hashCode())); // true
55 System.out.println();
56
57 // -------------------------------------------------------------------
58 // BOLUM 2: Compact constructor ile VALIDASYON
59 // -------------------------------------------------------------------
60 System.out.println("--- BOLUM 2: Compact constructor ile validasyon ---");
61 Para tutar = new Para(150.0, "TRY");
62 System.out.println("Gecerli para: " + tutar);
63 try {
64 new Para(-5.0, "TRY"); // negatif tutar -> compact constructor exception firlatir
65 } catch (IllegalArgumentException e) {
66 System.out.println("Validasyon yakalandi: " + e.getMessage());
67 }
68 try {
69 new Para(10.0, "EURO"); // gecersiz para birimi kodu (3 harf degil)
70 } catch (IllegalArgumentException e) {
71 System.out.println("Validasyon yakalandi: " + e.getMessage());
72 }
73 System.out.println();
74
75 // -------------------------------------------------------------------
76 // BOLUM 3: GERCEK HAYAT - Kullanici DTO + API response modeli
77 // -------------------------------------------------------------------
78 System.out.println("--- BOLUM 3: Gercek hayat - DTO ve API response ---");
79
80 KullaniciDTO kullanici = new KullaniciDTO(
81 42L, "ayse.yilmaz", "ayse@example.com", true);
82 System.out.println("Kullanici DTO: " + kullanici);
83 System.out.println("Aktif mi? : " + kullanici.aktif());
84
85 // Record icinde ek (turetilmis) metot da tanimlanabilir:
86 System.out.println("Maskelenmis email: " + kullanici.maskeliEmail());
87
88 // Generic record ile tipli API response:
89 ApiResponse<KullaniciDTO> response =
90 new ApiResponse<>(200, "OK", kullanici);
91 System.out.println("API response : " + response);
92 System.out.println("Basarili mi? : " + response.basarili());
93 System.out.println();
94
95 // -------------------------------------------------------------------
96 // BOLUM 4: Record'larin gucu - Map anahtari ve metottan coklu deger
97 // -------------------------------------------------------------------
98 System.out.println("--- BOLUM 4: Record'lar Map anahtari olarak ---");
99 // Otomatik equals/hashCode sayesinde record'lar dogrudan
100 // HashMap anahtari olarak GUVENLE kullanilabilir.
101 Map<Nokta, String> sehirler = Map.of(
102 new Nokta(41, 28), "Istanbul",
103 new Nokta(39, 32), "Ankara"
104 );
105 // Yeni ama ayni degerli bir Nokta ile arama yapsak da bulur:
106 System.out.println("(41,28) -> " + sehirler.get(new Nokta(41, 28)));
107
108 // Metottan birden fazla deger dondurmek icin record (tuple yerine):
109 MinMax mm = minMaxBul(List.of(7, 2, 9, 4, 1, 8));
110 System.out.println("Min/Max: " + mm + " -> min=" + mm.min() + " max=" + mm.max());
111 }
112
113 /** Listenin min ve max degerini TEK donus degerinde tasiyan yardimci. */
114 static MinMax minMaxBul(List<Integer> sayilar) {
115 int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
116 for (int s : sayilar) {
117 min = Math.min(min, s);
118 max = Math.max(max, s);
119 }
120 return new MinMax(min, max);
121 }
122
123 // =========================================================================
124 // ESKI YOL: Klasik immutable POJO/DTO -- ~50 satir BOILERPLATE
125 // (record olmadan bir 2D nokta yazmak icin tum bunlar gerekir)
126 // =========================================================================
127 static final class NoktaEski {
128 private final int x;
129 private final int y;
130
131 public NoktaEski(int x, int y) {
132 this.x = x;
133 this.y = y;
134 }
135
136 public int getX() { return x; }
137 public int getY() { return y; }
138
139 @Override
140 public boolean equals(Object o) {
141 if (this == o) return true;
142 if (o == null || getClass() != o.getClass()) return false;
143 NoktaEski that = (NoktaEski) o;
144 return x == that.x && y == that.y;
145 }
146
147 @Override
148 public int hashCode() {
149 return Objects.hash(x, y);
150 }
151
152 @Override
153 public String toString() {
154 return "NoktaEski{x=" + x + ", y=" + y + "}";
155 }
156 }
157
158 // =========================================================================
159 // YENI YOL: Yukaridaki ~50 satirin HEPSININ karsiligi -> TEK SATIR
160 // =========================================================================
161 record Nokta(int x, int y) { }
162 // -> private final int x, y
163 // -> public Nokta(int x, int y) { ... } (canonical constructor)
164 // -> public int x(), public int y() (accessor'lar)
165 // -> equals / hashCode / toString (deger tabanli)
166
167 // =========================================================================
168 // COMPACT CONSTRUCTOR ile validasyon iceren record.
169 // "Para(double tutar, String birim)" yazmadan, parametre listesi
170 // olmayan kompakt yapilandirici icinde dogrulama yapilir; alanlar
171 // atama gerektirmez (Java otomatik atar).
172 // =========================================================================
173 record Para(double tutar, String birim) {
174 Para { // <-- compact constructor (parametre parantezi YOK)
175 if (tutar < 0) {
176 throw new IllegalArgumentException("Tutar negatif olamaz: " + tutar);
177 }
178 if (birim == null || birim.length() != 3) {
179 throw new IllegalArgumentException(
180 "Para birimi 3 harfli ISO kodu olmali (orn. TRY, USD): " + birim);
181 }
182 }
183 }
184
185 // =========================================================================
186 // GERCEK HAYAT: Kullanici DTO (REST API'de tasinan veri)
187 // Record icinde ek/turetilmis metot tanimlanabilir.
188 // =========================================================================
189 record KullaniciDTO(long id, String kullaniciAdi, String email, boolean aktif) {
190 /** Email'i loglarda gizlemek icin maskeleyen turetilmis metot. */
191 String maskeliEmail() {
192 int at = email.indexOf('@');
193 if (at <= 1) return "***";
194 return email.charAt(0) + "***" + email.substring(at);
195 }
196 }
197
198 // =========================================================================
199 // GERCEK HAYAT: Generic API response modeli
200 // =========================================================================
201 record ApiResponse<T>(int statusKodu, String mesaj, T veri) {
202 boolean basarili() {
203 return statusKodu >= 200 && statusKodu < 300;
204 }
205 }
206
207 // =========================================================================
208 // Metottan birden fazla deger dondurmek icin kucuk record (tuple yerine)
209 // =========================================================================
210 record MinMax(int min, int max) { }
211}SwitchExpressionsKalici
çalıştırılabilir1/*
2 * =============================================================================
3 * Java 14 - SWITCH EXPRESSIONS (ARTIK KALICI / STANDART)
4 * JEP 361: Switch Expressions
5 * =============================================================================
6 *
7 * PREVIEW -> KALICI EVRIMI (cok onemli):
8 * - Java 12: Switch Expressions ILK preview olarak geldi.
9 * - Java 13: 2. preview oldu ("yield" anahtar kelimesi eklendi).
10 * - Java 14: ARTIK KALICI! Standart dilin parcasi.
11 *
12 * Bu, su anlama gelir:
13 * -> Java 14 ve sonrasinda switch expressions kullanmak icin
14 * "--enable-preview" bayragina ARTIK GEREK YOKTUR.
15 * -> Normal "javac Dosya.java" ile derlenir.
16 *
17 * Derleme/Calistirma (Java 14+):
18 * javac SwitchExpressionsKalici.java
19 * java SwitchExpressionsKalici
20 * =============================================================================
21 */
22public class SwitchExpressionsKalici {
23
24 // ---- Ornek enum'lar (gercek hayat senaryolari icin) ----
25 enum Gun { PAZARTESI, SALI, CARSAMBA, PERSEMBE, CUMA, CUMARTESI, PAZAR }
26
27 enum MusteriSegmenti { STANDART, GUMUS, ALTIN, PLATIN }
28
29 enum IslemTipi { PARA_CEKME, PARA_YATIRMA, HAVALE, EFT, DOVIZ_ALIM }
30
31 public static void main(String[] args) {
32 System.out.println("=== Java 14: Switch Expressions (KALICI) ===\n");
33
34 // -------------------------------------------------------------------
35 // 1) ESKI YOL vs YENI YOL: Gun -> "hafta ici mi?" bilgisi
36 // -------------------------------------------------------------------
37 // ESKI (klasik switch deyimi): degisken disarida tanimlanir,
38 // her case icinde elle atanir, "break" unutma riski vardir.
39 Gun bugun = Gun.CUMARTESI;
40
41 String eskiSonuc; // once tanimla
42 switch (bugun) {
43 case CUMARTESI:
44 case PAZAR:
45 eskiSonuc = "Hafta sonu";
46 break; // break unutulursa fall-through!
47 default:
48 eskiSonuc = "Hafta ici";
49 break;
50 }
51 System.out.println("ESKI switch deyimi -> " + eskiSonuc);
52
53 // YENI (switch EXPRESSION): dogrudan deger DONDURUR, break YOK,
54 // fall-through riski YOK. Coklu case virgulle yazilir.
55 String yeniSonuc = switch (bugun) {
56 case CUMARTESI, PAZAR -> "Hafta sonu"; // -> oku otomatik break saglar
57 default -> "Hafta ici";
58 };
59 System.out.println("YENI switch expression -> " + yeniSonuc + "\n");
60
61 // -------------------------------------------------------------------
62 // 2) Deger dondurme + degiskene atama (ay -> gun sayisi)
63 // -------------------------------------------------------------------
64 int ay = 2; // Subat
65 int gunSayisi = switch (ay) {
66 case 1, 3, 5, 7, 8, 10, 12 -> 31;
67 case 4, 6, 9, 11 -> 30;
68 case 2 -> 28; // (artik yil ihmal edildi)
69 default -> throw new IllegalArgumentException("Gecersiz ay: " + ay);
70 };
71 System.out.println(ay + ". ayda " + gunSayisi + " gun var.\n");
72
73 // -------------------------------------------------------------------
74 // 3) "yield" ile cok satirli case blogu (deger dondurmek icin)
75 // -------------------------------------------------------------------
76 // Bir case'de birden fazla satir is yapip SONRA deger dondurmek
77 // gerekirse "{ ... yield deger; }" kullanilir.
78 Gun gun = Gun.CUMA;
79 int kalanIsGunu = switch (gun) {
80 case PAZARTESI -> 5;
81 case SALI -> 4;
82 case CARSAMBA -> 3;
83 case PERSEMBE -> 2;
84 case CUMA -> {
85 // Cok satirli hesaplama yapilabilir...
86 System.out.println(" (Cuma gunu: hafta sonuna 1 gun kaldi)");
87 int sonuc = 1;
88 yield sonuc; // yield ile deger dondur
89 }
90 case CUMARTESI, PAZAR -> 0;
91 };
92 System.out.println("Hafta sonuna kalan is gunu: " + kalanIsGunu + "\n");
93
94 // -------------------------------------------------------------------
95 // GERCEK HAYAT ORNEGI 1: E-ticaret indirim orani (musteri segmenti)
96 // -------------------------------------------------------------------
97 System.out.println("--- Gercek Hayat: E-ticaret indirim orani ---");
98 for (MusteriSegmenti s : MusteriSegmenti.values()) {
99 double indirim = indirimOrani(s);
100 System.out.printf(" %-8s -> %%%.0f indirim%n", s, indirim * 100);
101 }
102 System.out.println();
103
104 // -------------------------------------------------------------------
105 // GERCEK HAYAT ORNEGI 2: Bankacilik islem komisyonu
106 // -------------------------------------------------------------------
107 System.out.println("--- Gercek Hayat: Banka islem komisyonu (1000 TL islem) ---");
108 double tutar = 1000.0;
109 for (IslemTipi t : IslemTipi.values()) {
110 double komisyon = komisyonHesapla(t, tutar);
111 System.out.printf(" %-12s -> %.2f TL komisyon%n", t, komisyon);
112 }
113 }
114
115 /**
116 * Musteri segmentine gore indirim orani dondurur.
117 * Switch expression sayesinde tek satirda, fall-through riski olmadan.
118 */
119 static double indirimOrani(MusteriSegmenti segment) {
120 return switch (segment) {
121 case STANDART -> 0.00; // %0
122 case GUMUS -> 0.05; // %5
123 case ALTIN -> 0.10; // %10
124 case PLATIN -> 0.20; // %20
125 };
126 // NOT: enum'in tum degerleri kapsanmissa "default" gerekmez;
127 // derleyici "exhaustiveness" (tamlik) kontrolu yapar.
128 }
129
130 /**
131 * Islem tipine ve tutara gore komisyon hesaplar.
132 * Cok satirli mantik gerektiren case'lerde "yield" kullanilir.
133 */
134 static double komisyonHesapla(IslemTipi tip, double tutar) {
135 return switch (tip) {
136 case PARA_YATIRMA -> 0.0; // ucretsiz
137 case PARA_CEKME -> 2.0; // sabit ucret
138 case HAVALE -> tutar * 0.001; // binde 1
139 case EFT -> {
140 double oran = tutar * 0.002; // binde 2
141 double minUcret = 3.0; // en az 3 TL
142 yield Math.max(oran, minUcret);
143 }
144 case DOVIZ_ALIM -> tutar * 0.005; // binde 5
145 };
146 }
147}