Java 22 (Mart 2024) — Detaylı Türkçe Analiz
| Özellik | Değer | |--------------------|--------------------------------------------------------------| | Sürüm | Java SE 22 / JDK 22 | | Çıkış tarihi | 19 Mart 2024 | | Tür | Feature release (non-LTS) — kısa destek…
Java 22 (Mart 2024) — Detaylı Türkçe Analiz
Sürüm Bilgisi
| Özellik | Değer |
|---|---|
| Sürüm | Java SE 22 / JDK 22 |
| Çıkış tarihi | 19 Mart 2024 |
| Tür | Feature release (non-LTS) — kısa destekli ara sürüm |
| Önceki LTS | Java 21 (Eylül 2023) |
| Sonraki LTS | Java 25 (Eylül 2025) |
| Toplam JEP sayısı | 12 |
Not — non-LTS ne demek? Java 22, üretim ortamı için uzun vadeli destek (LTS) almayan bir ara sürümdür. Genellikle yeni özellikleri denemek, kütüphane uyumluluğunu test etmek ve bir sonraki LTS'e (Java 25) hazırlanmak için kullanılır. Üretimde uzun ömür isteyen ekipler LTS sürümlerde (17, 21, 25 ...) kalmayı tercih eder.
Bu dokümandaki özellikler ve durumları
| JEP | Özellik | Durum (Java 22) | İlgili dosya |
|---|---|---|---|
| 454 | Foreign Function & Memory API | KALICI (stable) | ForeignFunctionMemoryApi.java |
| 456 | Unnamed Variables & Patterns | KALICI (stable) | UnnamedVariables.java |
| 461 | Stream Gatherers | Preview (önizleme) | StreamGatherersPreview.java |
| 447 | Statements before super(...) | Preview (önizleme) | (sadece bu README'de) |
| 458 | Launch Multi-File Source-Code Programs | KALICI (stable) | (sadece bu README'de) |
| 423 | Region Pinning for G1 | KALICI (stable) | (sadece bu README'de) |
Genel Bakış
Java 22'nin öne çıkan başlığı, Project Panama'nın olgunlaşmasıyla Foreign Function & Memory (FFM) API'nin artık kalıcı/standart hale gelmesidir. Bu, JNI'nin (Java Native Interface) modern, güvenli ve performanslı alternatifidir ve C/C++ kütüphanelerini çağırmayı köklü biçimde kolaylaştırır.
Bunun yanında Unnamed Variables & Patterns (alt çizgi _) kalıcı hale
gelerek kullanılmayan değişkenleri ifade etmeyi standartlaştırdı.
Stream Gatherers ise Stream API'ye özel ara operasyon yazma yeteneği
getiren (henüz preview) güçlü bir eklemedir.
1. Foreign Function & Memory API — JEP 454 (KALICI)
NEDİR?
java.lang.foreign paketi altında, Java kodundan yerel (native) kod ve
kütüphaneleri çağırmayı ve JVM yığını dışındaki (off-heap) belleği güvenli
biçimde yönetmeyi sağlayan API'dir. Project Panama'nın ürünüdür.
NEDEN GELDİ?
Onlarca yıldır native kod çağırmanın tek "resmi" yolu JNI idi. JNI:
- Ayrı C/C++ ara katman (glue) kodu yazmayı zorunlu kılar,
- Bu kodu derleyip ayrı bir paylaşımlı kütüphane (.so/.dll/.dylib) üretmeyi gerektirir,
- Kırılgan, hata yapmaya açık (manuel referans yönetimi, çökme riski),
- Bakımı pahalı ve platforma bağımlıdır.
FFM bu adımların tamamını ortadan kaldırır: ara C kodu YAZMADAN, doğrudan Java'dan native fonksiyon çağrılır.
NE İŞE YARAR?
- İşletim sisteminin C kütüphanesi (libc) fonksiyonlarını çağırma,
- Üçüncü parti C/C++ kütüphanelerini (OpenSSL, SQLite, BLAS, CUDA sarmalayıcı vb.) kullanma,
- Büyük/uzun ömürlü veriyi GC baskısı olmadan off-heap bellekte tutma.
NEREDE KOLAYLIK SAĞLAR?
- Yüksek performanslı yerel kütüphane entegrasyonları,
- Büyük veri tamponları (görüntü/ses işleme, ağ tamponları),
- Mevcut C ekosistemini Java'ya köprülemek.
Temel Bileşenler
| Bileşen | Görevi |
|---|---|
Linker | Java ↔ native ABI köprüsü (Linker.nativeLinker()) |
SymbolLookup | Kütüphanedeki fonksiyon sembollerinin (adreslerinin) bulunması |
FunctionDescriptor | Native fonksiyon imzasının (dönüş + parametre) tanımı |
MethodHandle | Çağrılabilir handle — downcall (Java→native) |
upcallStub | Java metodunu native callback'e çevirir — upcall |
Arena | Bellek yaşam döngüsü yönetimi (try-with-resources ile güvenli) |
MemorySegment | Off-heap bellek bloğu (pointer'ın güvenli soyutlaması) |
ValueLayout | Bellek yerleşimi/boyutu (JAVA_INT, JAVA_LONG, ADDRESS...) |
ESKİ (JNI) vs YENİ (FFM)
ESKİ — JNI ile strlen çağırmak için gereken adımlar:
/* native.c — AYRICA derlenip .so/.dll yapılması gerekir */ #include <jni.h> #include <string.h> JNIEXPORT jlong JNICALL Java_Demo_strlen(JNIEnv *env, jobject obj, jstring s) { const char *cstr = (*env)->GetStringUTFChars(env, s, NULL); jlong len = (jlong) strlen(cstr); (*env)->ReleaseStringUTFChars(env, s, cstr); // unutulursa memory leak! return len; }
// Java tarafı public class Demo { static { System.loadLibrary("native"); } // .so/.dll yüklenmeli native long strlen(String s); }
javac,javah/-h,gcc -shared, doğrujava.library.pathderdi...
YENİ — FFM ile (sadece Java, ara C kodu YOK):
Linker linker = Linker.nativeLinker(); MethodHandle strlen = linker.downcallHandle( linker.defaultLookup().find("strlen").orElseThrow(), FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS)); try (Arena arena = Arena.ofConfined()) { MemorySegment cString = arena.allocateUtf8String("Merhaba"); long len = (long) strlen.invoke(cString); // bellek otomatik serbest kalır }
FFM'nin JNI'ye Göre Avantajları
- Güvenli bellek erişimi:
MemorySegmentsınır kontrolü yapar; rastgele pointer aritmetiği yerine denetimli erişim. - Yaşam döngüsü yönetimi:
Arena(özellikleofConfined) try-with-resources ile kapanınca tüm bellek deterministik ve güvenli serbest bırakılır — use-after-free ve leak riski azalır. - Ara C kodu yok: Derleme/bağlama zinciri ortadan kalkar.
- İki yönlü: downcall (Java→native) ve upcall (native→Java callback) destekli.
GERÇEK HAYAT ÖRNEĞİ
Bir görüntü işleme uygulaması, hızlı bir C kütüphanesindeki (ör. libjpeg/libpng)
çözme fonksiyonunu çağırıp sonucu büyük bir off-heap MemorySegment'te tutar;
böylece GC'yi büyük byte dizileriyle yormaz. ForeignFunctionMemoryApi.java
dosyasında bunun çekirdeği gösterilmiştir: libc'den strlen, abs (downcall)
ve qsort (Java karşılaştırıcıyı upcall olarak vererek) çağrılır.
➡️ İlgili dosya: ForeignFunctionMemoryApi.java
Derleme: javac --release 22 ForeignFunctionMemoryApi.java
Çalıştırma: java --enable-native-access=ALL-UNNAMED ForeignFunctionMemoryApi
Geçişte Ne Değişti / Avantaj / Dezavantaj / Risk
- Değişti: Java 19–21'de preview olan API artık Java 22'de
--enable-previewGEREKTİRMEZ. Paket/sınıf adları stabil; ileri uyumlu kullanılabilir. - Avantaj: Daha az kod, daha güvenli bellek, daha kolay bakım, daha iyi performans potansiyeli.
- Dezavantaj/Risk: Native çağrı doğası gereği hâlâ "güvensiz" bir sınırdır;
yanlış imza/yerleşim JVM çökmesine yol açabilir. Çalışma zamanında
--enable-native-accessile izin gerekir (aksi halde uyarı). Platform/ABI farklılıkları taşınabilirliği etkileyebilir.
2. Unnamed Variables & Patterns — JEP 456 (KALICI)
NEDİR?
Tek alt çizgi _ ile isimsiz değişken ve isimsiz pattern bildirme
yeteneği. "Bunu bilerek kullanmıyorum" niyetini sözdiziminde açıkça ifade eder.
NEDEN GELDİ?
Çoğu zaman bir değişkeni bildirmek zorunda kalır ama kullanmayız: catch'te
yakalanan exception, lambda'nın ikinci parametresi, sadece sayım için dönen
döngü değişkeni, record'un ilgilenmediğimiz bileşeni... Bunlara unused,
ignored gibi sahte isimler vermek hem gürültü yaratır hem de derleyici/IDE
"kullanılmıyor" uyarısı doğurur.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR?
Niyeti netleştirir, gürültüyü ve yanlış uyarıları azaltır. Kullanım yerleri:
- Yerel değişken atamaları,
fordöngüleri, catch (Exception _),try (var _ = ...),- Lambda parametreleri
(k, _) -> ..., - Pattern matching'de unnamed pattern:
case Point(int x, _).
Aynı kapsamda birden fazla
_kullanılabilir; çünkü_bir isim değildir ve ona erişilemez — bu yüzden çakışmaz.
ESKİ vs YENİ
// ESKİ try { ... } catch (NumberFormatException e) { /* e kullanılmıyor ama bildirmek zorunda */ } map.forEach((key, value) -> kullan(key)); // value gereksiz isim, uyarı verir if (obj instanceof Point(int x, int y)) { kullan(x); } // y boşuna // YENİ (Java 22) try { ... } catch (NumberFormatException _) { } // niyet açık map.forEach((key, _) -> kullan(key)); // value yok, uyarı yok if (obj instanceof Point(int x, _)) { kullan(x); } // y atlandı
GERÇEK HAYAT ÖRNEĞİ
Bir konfigürasyon ayrıştırıcıda, sözlüğün sadece anahtarlarıyla ilgilenip
değerleri yok saymak, ya da bir koordinat record'unun yalnızca bir bileşenini
çekmek. UnnamedVariables.java 7 farklı kullanım senaryosunu gösterir.
➡️ İlgili dosya: UnnamedVariables.java
Derleme: javac --release 22 UnnamedVariables.java (preview gerekmez)
Geçişte Ne Değişti / Avantaj / Dezavantaj / Risk
- Değişti: Java 21'de preview olan özellik Java 22'de kalıcı.
- Avantaj: Daha temiz, niyeti açık kod; daha az uyarı.
- Risk: Çok eski kodda
_bir değişken adı olarak kullanılmış olabilir; Java 9'dan beri_'ın yalnız başına identifier olması zaten yasaklanmıştı, bu yüzden pratikte çakışma çok düşüktür.
3. Stream Gatherers — JEP 461 (PREVIEW)
NEDİR?
Stream.gather(Gatherer) ile özel ara (intermediate) stream operasyonları
yazma yeteneği. Terminal taraftaki Collector'ın ara-operasyon karşılığı gibidir.
NEDEN GELDİ?
Stream API'nin ara operasyon kümesi sabitti (map, filter, flatMap,
limit...). Kayan pencere, ardışık tekrarları eleme, koşullu erken durdurma
gibi ihtiyaçlar için bunları zincirlemek zor veya imkânsızdı. Gatherer,
durum (state) tutabilen, eleman yayabilen, hatta akışı erken sonlandırabilen
genişletilebilir bir mekanizma sunar.
NE İŞE YARAR — Hazır gatherer'lar
windowFixed(n)— ardışık n'li bloklar (batch),windowSliding(n)— n boyutlu kayan pencere (moving average vb.),fold(init, fn)— tek sonuca katlama,scan(init, fn)— kümülatif/running ara sonuçlar.
Gatherer'ın 4 bileşeni
initializer (state kur) · integrator (her elemanı işle, downstream'e yay) ·
combiner (paralel state birleştirme) · finisher (akış sonunda kalanı yay).
ESKİ vs YENİ — kayan pencere
// ESKİ: elle indeksleme, hata yapmaya açık döngü for (int i = 0; i + 3 <= list.size(); i++) { var pencere = list.subList(i, i + 3); ... } // YENİ (Java 22, preview): stream.gather(Gatherers.windowSliding(3)).map(...)...
GERÇEK HAYAT ÖRNEĞİ
Finans/IoT verisinde hareketli ortalama, ölçümleri batch'lere bölme,
kümülatif toplam, veya log akışında ardışık yinelenen satırları
sıkıştırma. StreamGatherersPreview.java hem hazır gatherer'ları hem de iki
özel gatherer (ardışık tekrarsız + eşik aşılınca erken durdurma) içerir.
➡️ İlgili dosya: StreamGatherersPreview.java
Derleme: javac --release 22 --enable-preview StreamGatherersPreview.java
Çalıştırma: java --enable-preview StreamGatherersPreview
Geçişte Ne Değişti / Avantaj / Dezavantaj / Risk
- Durum: Java 22'de preview (Java 23'te 2. preview, Java 24'te kalıcı).
- Avantaj: Stream'i genişletilebilir kılar; tekrar kullanılabilir özel operasyonlar.
- Dezavantaj/Risk: Preview olduğu için API ileride değişebilir; üretimde
dikkatli kullanılmalı.
--enable-previewile derlenen sınıflar yalnızca aynı sürümün JVM'inde ve yine--enable-previewile çalışır.
4. Statements before super(...) — JEP 447 (PREVIEW)
NEDİR? (kısa)
Bir kurucu (constructor) içinde, super(...) veya this(...) çağrısından
önce çalışan ifadelere (argümanları doğrulama, hazırlama, dönüştürme) izin
verir — yan etki this'e dokunmadığı sürece.
NEDEN / NE İŞE YARAR
Eskiden super(...) kurucunun ilk ifadesi olmak zorundaydı. Argüman doğrulaması
gibi mantıkları ya yardımcı static metoda taşımak ya da iç içe ifadelere
sıkıştırmak gerekiyordu.
// ESKİ: doğrulama, super argümanının içine gömülür Foo(int x) { super(dogrula(x)); } // ayrı static metot gerekir // YENİ (preview): super'den önce ifade Foo(int x) { if (x < 0) throw new IllegalArgumentException("x negatif olamaz"); super(x); }
Durum: Java 22'de preview. Derleme
--enable-previewgerektirir.
5. Launch Multi-File Source-Code Programs — JEP 458 (KALICI)
NEDİR? (kısa)
java başlatıcısının (launcher) "kaynak-dosya modu" artık birden fazla
.java dosyasına yayılan programları, önceden javac ile derlemeye gerek
kalmadan çalıştırabilir.
# Tek komut: birinci dosya ana sınıf; bağımlı .java dosyaları otomatik derlenir java Main.java
Hızlı prototipleme, öğretim ve küçük araçlar için derle-çalıştır adımını kaldırır. Java 11'deki tek-dosya kaynak modunun çok-dosyaya genişlemişidir.
6. Region Pinning for G1 — JEP 423 (KALICI)
NEDİR? (kısa)
G1 çöp toplayıcısında, JNI kritik bölgeleri (ör. GetPrimitiveArrayCritical)
sırasında GC'nin tamamen durmasını engelleyen bölge "pinleme" (sabitleme)
iyileştirmesi.
NE İŞE YARAR
Eskiden bir thread native kod için bir diziyi "kritik" olarak kilitlediğinde G1, çakışmamak için GC'yi geciktirebiliyordu (gecikme/latency artışı). Region pinning ile yalnızca ilgili bölgeler sabitlenir; GC çalışmaya devam edebilir.
Avantaj: JNI ağırlıklı uygulamalarda daha düşük GC duraklaması ve daha az verim kaybı. Kod değişikliği gerektirmez — JVM içi iyileştirmedir.
Derleme/Çalıştırma Özeti
| Dosya | Derleme | Çalıştırma |
|---|---|---|
ForeignFunctionMemoryApi.java | javac --release 22 ForeignFunctionMemoryApi.java | java --enable-native-access=ALL-UNNAMED ForeignFunctionMemoryApi |
UnnamedVariables.java | javac --release 22 UnnamedVariables.java | java UnnamedVariables |
StreamGatherersPreview.java | javac --release 22 --enable-preview StreamGatherersPreview.java | java --enable-preview StreamGatherersPreview |
Önizleme (preview) özellikler için derleme ve çalıştırmada
--enable-previewşarttır. Kalıcı özellikler (FFM, Unnamed) için gerekmez.
Özet
Java 22, FFM API'yi kalıcı yaparak native entegrasyonu JNI'siz, güvenli ve modern bir hale getirdi; Unnamed Variables'ı standartlaştırarak kod netliğini artırdı; Stream Gatherers ile Stream API'yi genişletilebilir kıldı (preview). Bir non-LTS sürüm olarak, asıl hedef bu yenilikleri Java 25 LTS'ten önce olgunlaştırmaktı.
▶ Kod Örnekleri(3)
ForeignFunctionMemoryApi
ortam gerekir1// =============================================================================
2// Java 22 - Foreign Function & Memory (FFM) API (JEP 454 - KALICI / STABLE)
3// =============================================================================
4//
5// ÖNEMLİ NOT:
6// -----------
7// FFM API, Java 19/20/21 boyunca "preview" (önizleme) olarak ilerledi.
8// JAVA 22 ile birlikte ARTIK STANDART (non-preview / kalıcı) hale geldi.
9// Yani bu dosyayı --enable-preview bayrağına GEREK OLMADAN derleyebilirsin.
10//
11// DERLEME:
12// javac --release 22 ForeignFunctionMemoryApi.java
13//
14// ÇALIŞTIRMA (native erişim uyarısını susturmak için --enable-native-access):
15// java --enable-native-access=ALL-UNNAMED ForeignFunctionMemoryApi
16//
17// NOT: java.lang.foreign paketi modülünde olduğu için ek bir --add-modules
18// bayrağına gerek yoktur (java.base içindedir).
19//
20// Bu örnek, işletim sisteminin STANDART C KÜTÜPHANESİ (libc) içindeki
21// fonksiyonları Java'dan, JNI YAZMADAN doğrudan çağırır:
22// - strlen(const char*) : bir C string'in uzunluğunu döner
23// - abs(int) : tam sayının mutlak değeri
24// - printf(const char*) : C tarafında ekrana yazar (upcall'a benzemese de
25// variadic fonksiyon çağrısına örnektir)
26//
27// Ayrıca bir UPCALL örneği de var: Java tarafında yazılmış bir karşılaştırma
28// fonksiyonunu, C standart kütüphanesinin qsort fonksiyonuna geri-çağrı
29// (callback) olarak veriyoruz.
30// =============================================================================
31
32import java.lang.foreign.Arena;
33import java.lang.foreign.FunctionDescriptor;
34import java.lang.foreign.Linker;
35import java.lang.foreign.MemorySegment;
36import java.lang.foreign.SymbolLookup;
37import java.lang.foreign.ValueLayout;
38import java.lang.invoke.MethodHandle;
39import java.lang.invoke.MethodHandles;
40import java.lang.invoke.MethodType;
41
42public class ForeignFunctionMemoryApi {
43
44 public static void main(String[] args) throws Throwable {
45
46 System.out.println("=== Java 22 Foreign Function & Memory (FFM) API ===\n");
47
48 // ---------------------------------------------------------------------
49 // 1) TEMEL KAVRAMLAR
50 // ---------------------------------------------------------------------
51 // Linker : Java ile native (yerel) ABI arasındaki köprü.
52 // Linker.nativeLinker() platformun C ABI'sini verir.
53 // SymbolLookup : Bir kütüphanedeki fonksiyon sembollerini (adreslerini)
54 // bulmamızı sağlar.
55 // FunctionDescriptor : Native fonksiyonun imzasını (dönüş + parametre
56 // tiplerini) tanımlar.
57 // MethodHandle : Çağrılabilir Java referansı; native fonksiyonu
58 // buradan invoke ederiz (downcall).
59 // Arena : Bellek (MemorySegment) yaşam döngüsünü yönetir.
60 // try-with-resources ile kapanınca tüm bellek
61 // GÜVENLİ biçimde serbest bırakılır.
62 // MemorySegment : Off-heap (yığın dışı / native) bellek bloğu.
63 // ValueLayout : Bir değerin bellekteki yerleşimini/boyutunu tanımlar
64 // (ör. JAVA_INT, JAVA_BYTE, ADDRESS).
65 // ---------------------------------------------------------------------
66
67 Linker linker = Linker.nativeLinker();
68
69 // Standart C kütüphanesinin sembollerini bul (libc / msvcrt vb.).
70 // Linker'ın varsayılan lookup'ı, platformun standart kütüphanesini içerir.
71 SymbolLookup stdLib = linker.defaultLookup();
72
73 // =====================================================================
74 // ÖRNEK 1: C strlen() fonksiyonunu çağırma (DOWNCALL)
75 // =====================================================================
76 // C imzası: size_t strlen(const char *s);
77 // - Dönüş tipi: size_t -> 64-bit platformda JAVA_LONG
78 // - Parametre : const char* -> ADDRESS (bir bellek adresi / pointer)
79 ornekStrlen(linker, stdLib);
80
81 // =====================================================================
82 // ÖRNEK 2: C abs() fonksiyonu (DOWNCALL, sadece skaler tipler)
83 // =====================================================================
84 // C imzası: int abs(int n);
85 ornekAbs(linker, stdLib);
86
87 // =====================================================================
88 // ÖRNEK 3: C qsort() ile UPCALL (Java callback'i C'ye verme)
89 // =====================================================================
90 // C imzası: void qsort(void *base, size_t nmemb, size_t size,
91 // int (*compar)(const void *, const void *));
92 ornekQsortUpcall(linker, stdLib);
93
94 System.out.println("\n=== Tüm FFM örnekleri tamamlandı ===");
95 }
96
97 // -------------------------------------------------------------------------
98 // ÖRNEK 1: strlen
99 // -------------------------------------------------------------------------
100 private static void ornekStrlen(Linker linker, SymbolLookup stdLib) throws Throwable {
101 System.out.println("--- ÖRNEK 1: C strlen() çağrısı ---");
102
103 // strlen sembolünü bul. Bulunamazsa Optional boş döner.
104 MemorySegment strlenAddr = stdLib.find("strlen")
105 .orElseThrow(() -> new RuntimeException("strlen sembolü bulunamadı"));
106
107 // Fonksiyon imzasını tanımla:
108 // dönüş: JAVA_LONG (size_t), parametre: ADDRESS (const char*)
109 FunctionDescriptor strlenDesc =
110 FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS);
111
112 // Çağrılabilir MethodHandle (downcall handle) üret.
113 MethodHandle strlen = linker.downcallHandle(strlenAddr, strlenDesc);
114
115 // Arena: ayırdığımız native belleğin yaşam döngüsünü yönetir.
116 // try-with-resources bloğu bitince bellek otomatik ve GÜVENLİ serbest kalır.
117 // (Manuel free() çağrısı YOK -> memory leak ve use-after-free riski düşer.)
118 try (Arena arena = Arena.ofConfined()) {
119 String metin = "Merhaba FFM API!";
120
121 // Java String'i, C'nin beklediği NUL ('\0') ile sonlanan
122 // bir byte dizisine çevirip native belleğe yaz.
123 // NOT: Java 22'de bu metot allocateFrom(String) adındadır.
124 // (Java 21 preview'da adı allocateUtf8String idi -> yeniden adlandırıldı.)
125 MemorySegment cString = arena.allocateFrom(metin);
126
127 // Native fonksiyonu çağır. Dönüş long (size_t).
128 long uzunluk = (long) strlen.invoke(cString);
129
130 System.out.println(" Metin : \"" + metin + "\"");
131 System.out.println(" Java length : " + metin.length());
132 System.out.println(" C strlen() : " + uzunluk + " byte (UTF-8 byte sayısı)");
133 // Not: Türkçe karakter içermediği için bu metinde length == strlen.
134 // 'ç','ş' gibi çok-baytlı UTF-8 karakterlerde C strlen byte sayar,
135 // Java length ise UTF-16 kod birimi sayar -> farklı olabilir.
136 }
137 System.out.println();
138 }
139
140 // -------------------------------------------------------------------------
141 // ÖRNEK 2: abs
142 // -------------------------------------------------------------------------
143 private static void ornekAbs(Linker linker, SymbolLookup stdLib) throws Throwable {
144 System.out.println("--- ÖRNEK 2: C abs() çağrısı ---");
145
146 MemorySegment absAddr = stdLib.find("abs")
147 .orElseThrow(() -> new RuntimeException("abs sembolü bulunamadı"));
148
149 // int abs(int) -> dönüş JAVA_INT, parametre JAVA_INT
150 FunctionDescriptor absDesc =
151 FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT);
152
153 MethodHandle abs = linker.downcallHandle(absAddr, absDesc);
154
155 // Skaler tip olduğu için Arena'ya gerek yok (bellek ayırmıyoruz).
156 int sonuc = (int) abs.invoke(-12345);
157 System.out.println(" abs(-12345) = " + sonuc);
158 System.out.println();
159 }
160
161 // -------------------------------------------------------------------------
162 // ÖRNEK 3: qsort + UPCALL (Java karşılaştırıcısını C'ye callback olarak ver)
163 // -------------------------------------------------------------------------
164 private static void ornekQsortUpcall(Linker linker, SymbolLookup stdLib) throws Throwable {
165 System.out.println("--- ÖRNEK 3: C qsort() + Java upcall (callback) ---");
166
167 MemorySegment qsortAddr = stdLib.find("qsort")
168 .orElseThrow(() -> new RuntimeException("qsort sembolü bulunamadı"));
169
170 // void qsort(void* base, size_t nmemb, size_t size, comparator)
171 FunctionDescriptor qsortDesc = FunctionDescriptor.ofVoid(
172 ValueLayout.ADDRESS, // base (dizinin adresi)
173 ValueLayout.JAVA_LONG, // nmemb (eleman sayısı)
174 ValueLayout.JAVA_LONG, // size (her elemanın byte boyutu)
175 ValueLayout.ADDRESS); // compar (karşılaştırıcı fonksiyon pointer'ı)
176
177 MethodHandle qsort = linker.downcallHandle(qsortAddr, qsortDesc);
178
179 try (Arena arena = Arena.ofConfined()) {
180 int[] veriler = { 42, 7, 1000, -3, 88, 0, 17 };
181 System.out.println(" Sıralama öncesi : " + java.util.Arrays.toString(veriler));
182
183 // Diziyi native belleğe int (4 byte) dizisi olarak ayır ve doldur.
184 // NOT: Java 22'de N elemanlık ayırma için allocate(layout, count) kullanılır.
185 // (Java 21 preview'da allocateArray(layout, count) idi -> yeniden adlandırıldı.)
186 MemorySegment nativeDizi =
187 arena.allocate(ValueLayout.JAVA_INT, veriler.length);
188 for (int i = 0; i < veriler.length; i++) {
189 nativeDizi.setAtIndex(ValueLayout.JAVA_INT, i, veriler[i]);
190 }
191
192 // ---- UPCALL: Java metodunu C'nin çağırabileceği bir adrese dönüştür ----
193 // C comparator imzası: int compar(const void* a, const void* b);
194 // Her iki parametre de elemanın adresidir (ADDRESS).
195 FunctionDescriptor comparatorDesc = FunctionDescriptor.of(
196 ValueLayout.JAVA_INT, // dönüş: int (<0, 0, >0)
197 ValueLayout.ADDRESS, // a
198 ValueLayout.ADDRESS); // b
199
200 // Java tarafındaki statik karşılaştırma metodumuza MethodHandle al.
201 MethodHandle comparatorHandle = MethodHandles.lookup().findStatic(
202 ForeignFunctionMemoryApi.class,
203 "intKarsilastir",
204 MethodType.methodType(int.class, MemorySegment.class, MemorySegment.class));
205
206 // Java handle'ını native bir fonksiyon pointer'ına (upcall stub) çevir.
207 MemorySegment comparatorPtr = linker.upcallStub(
208 comparatorHandle, comparatorDesc, arena);
209
210 // qsort'u çağır. C, sıralama sırasında bizim Java metodumuzu çağıracak.
211 qsort.invoke(
212 nativeDizi,
213 (long) veriler.length,
214 ValueLayout.JAVA_INT.byteSize(), // her int 4 byte
215 comparatorPtr);
216
217 // Sonucu native bellekten geri oku.
218 int[] sirali = new int[veriler.length];
219 for (int i = 0; i < veriler.length; i++) {
220 sirali[i] = nativeDizi.getAtIndex(ValueLayout.JAVA_INT, i);
221 }
222 System.out.println(" Sıralama sonrası: " + java.util.Arrays.toString(sirali));
223 System.out.println(" (Sıralamayı C qsort yaptı, karşılaştırmayı Java yaptı!)");
224 }
225 System.out.println();
226 }
227
228 /**
229 * C qsort tarafından çağrılan UPCALL hedefi.
230 * Parametreler, sıralanan int elemanlarının native ADRESLERİdir.
231 * Adresten gerçek int değerini okumak için segmenti yeniden yorumlarız.
232 *
233 * @param aPtr birinci elemanın adresi
234 * @param bPtr ikinci elemanın adresi
235 * @return a<b -> negatif, a==b -> 0, a>b -> pozitif
236 */
237 private static int intKarsilastir(MemorySegment aPtr, MemorySegment bPtr) {
238 // Gelen adresler boyutsuzdur; 4 byte'lık int olarak yeniden yorumla.
239 int a = aPtr.reinterpret(ValueLayout.JAVA_INT.byteSize())
240 .get(ValueLayout.JAVA_INT, 0);
241 int b = bPtr.reinterpret(ValueLayout.JAVA_INT.byteSize())
242 .get(ValueLayout.JAVA_INT, 0);
243 return Integer.compare(a, b);
244 }
245}Bu sürüm-analizi örneği tek dosya olarak yerel JDK 21 ile çalıştırılamadı (bağımsız bir main içermeyebilir ya da daha yeni bir JDK / önizleme özelliği gerektirir). İlgili dil özelliği yukarıdaki anlatım ve kodda gösterilmiştir.
StreamGatherersPreview
ortam gerekir1// =============================================================================
2// Java 22 - Stream Gatherers (JEP 461 - PREVIEW / ÖNİZLEME)
3// =============================================================================
4//
5// ÖNEMLİ NOT:
6// -----------
7// Stream Gatherers, Java 22'de PREVIEW (önizleme) özelliğidir.
8// Bu nedenle derlerken VE çalıştırırken --enable-preview GEREKLİDİR.
9// (Java 23'te ikinci preview, Java 24'te kalıcı hale gelmiştir; ama bu
10// dosya Java 22 hedefiyle hazırlanmıştır.)
11//
12// DERLEME:
13// javac --release 22 --enable-preview StreamGatherersPreview.java
14// ÇALIŞTIRMA:
15// java --enable-preview StreamGatherersPreview
16//
17// (NOT: --enable-preview olmadan derleme/çalıştırma HATA verir.)
18//
19// STREAM GATHERERS NEDİR?
20// -----------------------
21// Stream API'de filter / map / flatMap gibi sabit bir ara (intermediate)
22// operasyon kümesi vardı; KENDİ ara operasyonunu yazmak mümkün değildi.
23// Gatherer arayüzü bunu çözer: Stream.gather(Gatherer) ile ÖZEL ara
24// operasyonlar tanımlayabiliriz. Terminal taraftaki Collector'ın
25// "ara operasyon" karşılığı gibidir.
26//
27// HAZIR (built-in) GATHERER'LAR (java.util.stream.Gatherers):
28// - windowFixed(n) : ardışık n'li bloklara böler (kayan değil)
29// - windowSliding(n) : n boyutlu KAYAN pencereler üretir
30// - fold(init, fn) : tek bir sonuca katlar (akış sonunda 1 eleman yayar)
31// - scan(init, fn) : kümülatif/running ara sonuçları yayar
32//
33// Gatherer'ın 4 bileşeni vardır:
34// initializer() : (opsiyonel) durum (state) nesnesi oluşturur
35// integrator() : her elemanı işler, downstream'e eleman yayabilir
36// combiner() : (opsiyonel) paralel akışta state'leri birleştirir
37// finisher() : (opsiyonel) akış bitince kalan state'i yayar
38// =============================================================================
39
40import java.util.List;
41import java.util.stream.Gatherer;
42import java.util.stream.Gatherers;
43import java.util.stream.Stream;
44
45public class StreamGatherersPreview {
46
47 public static void main(String[] args) {
48 System.out.println("=== Java 22 Stream Gatherers (PREVIEW) ===\n");
49
50 ornek1_windowFixed();
51 ornek2_windowSliding();
52 ornek3_fold();
53 ornek4_scan();
54 ornek5_ozelGatherer_distinctArdisik();
55 ornek6_ozelGatherer_limitWhile();
56
57 System.out.println("\n=== Tüm gatherer örnekleri tamamlandı ===");
58 }
59
60 // -------------------------------------------------------------------------
61 // 1) windowFixed(n) : ardışık SABİT bloklar
62 // -------------------------------------------------------------------------
63 private static void ornek1_windowFixed() {
64 System.out.println("--- 1) Gatherers.windowFixed(3) ---");
65
66 // Gerçek hayat: 8 ölçüm değerini 3'erli partilere böl (batch işleme).
67 List<List<Integer>> bloklar = Stream.of(1, 2, 3, 4, 5, 6, 7, 8)
68 .gather(Gatherers.windowFixed(3))
69 .toList();
70
71 System.out.println(" 3'erli bloklar: " + bloklar);
72 // -> [[1,2,3],[4,5,6],[7,8]] (son blok eksik olabilir)
73 }
74
75 // -------------------------------------------------------------------------
76 // 2) windowSliding(n) : KAYAN pencere
77 // -------------------------------------------------------------------------
78 private static void ornek2_windowSliding() {
79 System.out.println("--- 2) Gatherers.windowSliding(3) ---");
80
81 // Gerçek hayat: hareketli ortalama (moving average) için 3'lü kayan
82 // pencereler oluştur.
83 List<Double> hareketliOrtalama = Stream.of(10, 20, 30, 40, 50)
84 .gather(Gatherers.windowSliding(3))
85 .map(pencere -> pencere.stream()
86 .mapToInt(Integer::intValue)
87 .average()
88 .orElse(0.0))
89 .toList();
90
91 System.out.println(" 3'lü kayan pencere ortalamaları: " + hareketliOrtalama);
92 // pencereler: [10,20,30],[20,30,40],[30,40,50] -> [20.0, 30.0, 40.0]
93 }
94
95 // -------------------------------------------------------------------------
96 // 3) fold(init, fn) : tek bir sonuca katla (akış sonunda 1 eleman)
97 // -------------------------------------------------------------------------
98 private static void ornek3_fold() {
99 System.out.println("--- 3) Gatherers.fold ---");
100
101 // Gerçek hayat: kelimeleri tek bir cümleye katla.
102 String cumle = Stream.of("Java", "22", "Stream", "Gatherers")
103 .gather(Gatherers.fold(
104 () -> "", // başlangıç değeri
105 (acc, kelime) -> acc.isEmpty()
106 ? kelime
107 : acc + " " + kelime)) // birleştirme
108 .findFirst()
109 .orElse("");
110
111 System.out.println(" fold sonucu: \"" + cumle + "\"");
112 }
113
114 // -------------------------------------------------------------------------
115 // 4) scan(init, fn) : kümülatif (running) sonuçları yay
116 // -------------------------------------------------------------------------
117 private static void ornek4_scan() {
118 System.out.println("--- 4) Gatherers.scan (kümülatif toplam) ---");
119
120 // Gerçek hayat: aylık gelirlerin kümülatif (yıl-içi birikimli) toplamı.
121 List<Integer> kumulatif = Stream.of(100, 200, 300, 400)
122 .gather(Gatherers.scan(() -> 0, (toplam, deger) -> toplam + deger))
123 .toList();
124
125 System.out.println(" Kümülatif toplamlar: " + kumulatif);
126 // -> [100, 300, 600, 1000]
127 }
128
129 // -------------------------------------------------------------------------
130 // 5) ÖZEL GATHERER: ardışık tekrarları temizle (distinctArdisik)
131 // [1,1,2,2,2,3,1] -> [1,2,3,1]
132 // (Stream.distinct globaldir; bu sadece ARDIŞIK tekrarı atar.)
133 // -------------------------------------------------------------------------
134 private static void ornek5_ozelGatherer_distinctArdisik() {
135 System.out.println("--- 5) ÖZEL Gatherer: ardışık tekrarları at ---");
136
137 List<Integer> sonuc = Stream.of(1, 1, 2, 2, 2, 3, 1, 1)
138 .gather(ardisikTekrarsiz())
139 .toList();
140
141 System.out.println(" Ardışık tekrarsız: " + sonuc);
142 // -> [1, 2, 3, 1]
143 }
144
145 /**
146 * State'li (durum tutan) özel bir Gatherer.
147 * Bir önceki elemanı hatırlar; yeni eleman ondan farklıysa downstream'e yayar.
148 *
149 * T tipi: giriş ve çıkış elemanları (aynı tip)
150 * state : son görülen değeri tutan tek elemanlı dizi (mutable kapsül)
151 */
152 private static <T> Gatherer<T, ?, T> ardisikTekrarsiz() {
153 return Gatherer.ofSequential(
154 // initializer: state = "henüz eleman görülmedi" işaretçili kapsül
155 () -> new Object[]{ false, null }, // [gorulduMu, sonDeger]
156 // integrator: her eleman için çalışır
157 Gatherer.Integrator.ofGreedy((state, eleman, downstream) -> {
158 boolean gorulduMu = (boolean) state[0];
159 @SuppressWarnings("unchecked")
160 T sonDeger = (T) state[1];
161
162 if (!gorulduMu || !java.util.Objects.equals(sonDeger, eleman)) {
163 state[0] = true;
164 state[1] = eleman;
165 // downstream.push: elemanı bir sonraki aşamaya yay.
166 // false dönerse akış erken sonlanmış demektir.
167 return downstream.push(eleman);
168 }
169 // Ardışık tekrar -> yayma, akışa devam et.
170 return true;
171 })
172 );
173 }
174
175 // -------------------------------------------------------------------------
176 // 6) ÖZEL GATHERER: koşul sağlandığı sürece al (limitWhile / takeWhile benzeri)
177 // Burada downstream.push'in false dönmesiyle ERKEN sonlandırmayı gösteriyoruz.
178 // -------------------------------------------------------------------------
179 private static void ornek6_ozelGatherer_limitWhile() {
180 System.out.println("--- 6) ÖZEL Gatherer: toplam belli eşiği aşana kadar al ---");
181
182 // Gerçek hayat: kümülatif toplam 100'ü aşana KADAR elemanları al,
183 // aşan elemandan SONRA akışı erken durdur.
184 List<Integer> sonuc = Stream.of(30, 40, 50, 60, 70)
185 .gather(toplamEsigeKadar(100))
186 .toList();
187
188 System.out.println(" Kümülatif toplam 100'ü aşana kadar: " + sonuc);
189 // 30 (top=30), 40 (top=70), 50 (top=120 -> bunu da al ama sonra dur)
190 // -> [30, 40, 50]
191 }
192
193 private static Gatherer<Integer, ?, Integer> toplamEsigeKadar(int esik) {
194 return Gatherer.ofSequential(
195 () -> new int[]{ 0 }, // state: kümülatif toplam
196 Gatherer.Integrator.of((state, eleman, downstream) -> {
197 state[0] += eleman;
198 boolean devam = downstream.push(eleman);
199 if (state[0] > esik) {
200 // Eşik aşıldı: bu elemanı yaydık ama akışı SONLANDIR.
201 return false; // false -> üst akışı erken bitir
202 }
203 return devam;
204 })
205 );
206 }
207}Bu sürüm-analizi örneği tek dosya olarak yerel JDK 21 ile çalıştırılamadı (bağımsız bir main içermeyebilir ya da daha yeni bir JDK / önizleme özelliği gerektirir). İlgili dil özelliği yukarıdaki anlatım ve kodda gösterilmiştir.
UnnamedVariables
ortam gerekir1// =============================================================================
2// Java 22 - Unnamed Variables & Patterns (JEP 456 - KALICI / STABLE)
3// =============================================================================
4//
5// ÖNEMLİ NOT:
6// -----------
7// Bu özellik Java 21'de preview, JAVA 22'de KALICI (final/standart) hale geldi.
8// Yani --enable-preview bayrağına GEREK YOKTUR.
9//
10// DERLEME:
11// javac --release 22 UnnamedVariables.java
12// ÇALIŞTIRMA:
13// java UnnamedVariables
14//
15// ÖZET:
16// Tek alt çizgi _ artık "isimsiz değişken / isimsiz pattern" anlamına gelir.
17// Kullanmayacağımız ama söz dizimi gereği bildirmek zorunda olduğumuz
18// değişkenleri _ ile işaretleriz. Bu hem kodu netleştirir ("bunu bilerek
19// kullanmıyorum" niyetini gösterir) hem de derleyici/IDE uyarılarını azaltır.
20//
21// KULLANIM YERLERİ:
22// 1) Atama / yerel değişken : var _ = pahaliHesap();
23// 2) for döngüsü sayacı / değişkeni
24// 3) catch bloğu parametresi : catch (Exception _) { ... }
25// 4) try-with-resources : try (var _ = ac()) { ... }
26// 5) Lambda parametresi : (k, _) -> ...
27// 6) Pattern matching - unnamed pattern : case Point(int x, _)
28//
29// NOT: Aynı kapsamda BİRDEN FAZLA _ kullanılabilir (çakışma vermez),
30// çünkü _ bir isim değildir; ona erişmek mümkün değildir.
31// =============================================================================
32
33import java.util.ArrayList;
34import java.util.List;
35import java.util.Map;
36import java.util.Queue;
37import java.util.LinkedList;
38
39public class UnnamedVariables {
40
41 // ---- Pattern matching örnekleri için kayıt (record) tipleri ----
42 sealed interface Sekil permits Nokta, Daire, Dikdortgen {}
43 record Nokta(int x, int y) implements Sekil {}
44 record Daire(Nokta merkez, double yaricap) implements Sekil {}
45 record Dikdortgen(Nokta solUst, Nokta sagAlt) implements Sekil {}
46
47 public static void main(String[] args) {
48 System.out.println("=== Java 22 Unnamed Variables & Patterns ===\n");
49
50 ornek1_yerelDegisken();
51 ornek2_forDongusu();
52 ornek3_catchBlogu();
53 ornek4_tryWithResources();
54 ornek5_lambdaParametresi();
55 ornek6_unnamedPattern();
56 ornek7_iciceUnnamedPattern();
57
58 System.out.println("\n=== Tüm örnekler tamamlandı ===");
59 }
60
61 // -------------------------------------------------------------------------
62 // 1) ISIMSIZ YEREL DEĞİŞKEN
63 // Bir metodun yan etkisi için çağrıldığı, dönüş değerinin
64 // gerçekten gerekmediği durumlar.
65 // -------------------------------------------------------------------------
66 private static void ornek1_yerelDegisken() {
67 System.out.println("--- 1) Isimsiz yerel değişken ---");
68
69 // queue.poll() yan etki olarak elemanı çıkarır; değeri umursamıyoruz.
70 Queue<String> kuyruk = new LinkedList<>(List.of("a", "b", "c"));
71
72 // ESKİ: int unused = ...; veya değeri gereksiz yere değişkene atama
73 // YENİ: _ ile "bu değeri bilerek kullanmıyorum" deriz.
74 var _ = kuyruk.poll(); // ilk elemanı at, sonucu umursama
75 System.out.println(" Bir eleman atıldı. Kalan kuyruk: " + kuyruk);
76 }
77
78 // -------------------------------------------------------------------------
79 // 2) FOR DÖNGÜSÜNDE ISIMSIZ DEĞİŞKEN
80 // Sadece "N kere yap" demek istediğimizde sayacı kullanmıyoruz.
81 // -------------------------------------------------------------------------
82 private static void ornek2_forDongusu() {
83 System.out.println("--- 2) for döngüsünde isimsiz değişken ---");
84
85 List<String> kelimeler = List.of("elma", "armut", "kiraz");
86
87 // enhanced-for: elemanı kullanmadan sadece sayım yapıyoruz.
88 int adet = 0;
89 for (var _ : kelimeler) {
90 adet++; // eleman değerini kullanmıyoruz, sadece sayıyoruz
91 }
92 System.out.println(" Liste eleman sayısı (eleman kullanılmadan): " + adet);
93 }
94
95 // -------------------------------------------------------------------------
96 // 3) CATCH BLOĞUNDA ISIMSIZ DEĞİŞKEN
97 // Exception nesnesini hiç kullanmayacaksak _ ile yakalarız.
98 // -------------------------------------------------------------------------
99 private static void ornek3_catchBlogu() {
100 System.out.println("--- 3) catch bloğunda isimsiz değişken ---");
101
102 String girdi = "abc";
103 int deger;
104 try {
105 deger = Integer.parseInt(girdi);
106 } catch (NumberFormatException _) { // exception nesnesini kullanmıyoruz
107 deger = -1; // geçersiz girdi -> varsayılan
108 }
109 System.out.println(" \"" + girdi + "\" -> " + deger + " (parse başarısızsa -1)");
110 }
111
112 // -------------------------------------------------------------------------
113 // 4) TRY-WITH-RESOURCES İÇİNDE ISIMSIZ DEĞİŞKEN
114 // Kaynağı sadece açıp kapatmak (kilit/scope) için kullanıyoruz;
115 // referansa hiç dokunmuyoruz.
116 // -------------------------------------------------------------------------
117 private static void ornek4_tryWithResources() {
118 System.out.println("--- 4) try-with-resources içinde isimsiz kaynak ---");
119
120 // AutoCloseable bir kaynak: kapanınca mesaj yazsın.
121 try (var _ = acKapatLog("VeritabaniBaglantisi")) {
122 System.out.println(" Kaynak kullanılıyor (ama referansına ihtiyaç yok)...");
123 }
124 // try bloğundan çıkınca close() otomatik çağrılır.
125 }
126
127 private static AutoCloseable acKapatLog(String ad) {
128 System.out.println(" [AÇILDI] " + ad);
129 return () -> System.out.println(" [KAPANDI] " + ad);
130 }
131
132 // -------------------------------------------------------------------------
133 // 5) LAMBDA PARAMETRESİNDE ISIMSIZ DEĞİŞKEN
134 // Bir parametreyi kullanmayacağımızda _ ile geçeriz.
135 // -------------------------------------------------------------------------
136 private static void ornek5_lambdaParametresi() {
137 System.out.println("--- 5) lambda parametresinde isimsiz değişken ---");
138
139 Map<String, Integer> stok = Map.of("kalem", 10, "defter", 5, "silgi", 0);
140
141 // Map.forEach(BiConsumer): value'yu kullanmadan sadece key'leri yaz.
142 System.out.print(" Ürünler: ");
143 List<String> urunler = new ArrayList<>();
144 stok.forEach((urun, _) -> urunler.add(urun)); // miktarı umursamıyoruz
145 System.out.println(urunler);
146
147 // Birden fazla _ aynı lambda içinde de olabilir (örnek amaçlı):
148 // (a, _) gibi -> sadece ilk parametreyi kullan.
149 }
150
151 // -------------------------------------------------------------------------
152 // 6) UNNAMED PATTERN (pattern matching içinde)
153 // Record desktructuring sırasında ilgilenmediğimiz bileşeni
154 // _ ile geçeriz. Tip bile yazmamıza gerek yok.
155 // -------------------------------------------------------------------------
156 private static void ornek6_unnamedPattern() {
157 System.out.println("--- 6) Unnamed pattern (record bileşeni atlama) ---");
158
159 Sekil[] sekiller = {
160 new Nokta(3, 7),
161 new Daire(new Nokta(0, 0), 5.0),
162 new Dikdortgen(new Nokta(0, 10), new Nokta(10, 0))
163 };
164
165 for (Sekil s : sekiller) {
166 String aciklama = switch (s) {
167 // Nokta'nın sadece x'iyle ilgileniyoruz, y'yi _ ile atlıyoruz.
168 case Nokta(int x, _) -> "Nokta, x = " + x + " (y göz ardı edildi)";
169
170 // Daire'nin sadece yarıçapıyla ilgileniyoruz, merkezi atlıyoruz.
171 case Daire(var _, double r) -> "Daire, yarıçap = " + r;
172
173 // Dikdörtgen'in iki köşesini de istemiyoruz -> her ikisi de _.
174 case Dikdortgen(var _, var _) -> "Dikdörtgen (köşeler göz ardı edildi)";
175 };
176 System.out.println(" " + aciklama);
177 }
178 }
179
180 // -------------------------------------------------------------------------
181 // 7) İÇ İÇE (NESTED) UNNAMED PATTERN
182 // Derin yapıların içinde sadece ihtiyacımız olan kısmı çekeriz.
183 // -------------------------------------------------------------------------
184 private static void ornek7_iciceUnnamedPattern() {
185 System.out.println("--- 7) İç içe unnamed pattern ---");
186
187 Object nesne = new Daire(new Nokta(4, 9), 2.5);
188
189 // Daire'nin merkezinin SADECE y koordinatını istiyoruz.
190 // merkez Nokta'sının içine girip x'i _ ile atlıyoruz.
191 if (nesne instanceof Daire(Nokta(_, int merkezY), double r)) {
192 System.out.println(" Dairenin merkez Y'si = " + merkezY
193 + ", yarıçap = " + r + " (merkez X ve diğerleri atlandı)");
194 }
195 }
196}Bu sürüm-analizi örneği tek dosya olarak yerel JDK 21 ile çalıştırılamadı (bağımsız bir main içermeyebilir ya da daha yeni bir JDK / önizleme özelliği gerektirir). İlgili dil özelliği yukarıdaki anlatım ve kodda gösterilmiştir.