Java 24 — Detaylı Sürüm Analizi (Türkçe)
> Bu doküman, Java 24 ile gelen önemli özellikleri "NEDİR / NEDEN GELDİ / NE İŞE YARAR / > NEREDE KOLAYLIK SAĞLAR / ESKİ vs YENİ / GERÇEK HAYAT ÖRNEĞİ" başlıkları altında > Türkçe olarak açıklar. Eğitim ve referans am…
Java 24 — Detaylı Sürüm Analizi (Türkçe)
Bu doküman, Java 24 ile gelen önemli özellikleri "NEDİR / NEDEN GELDİ / NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR / ESKİ vs YENİ / GERÇEK HAYAT ÖRNEĞİ" başlıkları altında Türkçe olarak açıklar. Eğitim ve referans amaçlıdır.
Sürüm Bilgisi
| Özellik | Değer |
|---|---|
| Sürüm | Java 24 (JDK 24) |
| Çıkış Tarihi | Mart 2025 |
| Destek Tipi | Non-LTS (özellik sürümü) — bir sonraki LTS Java 25'tir (Eylül 2025) |
| Geliştirme süreci | OpenJDK, 6 aylık sürüm kadansı |
| JEP sayısı | Bu sürümde çok sayıda JEP onaylandı (24'ün üzerinde) |
Not (LTS uyarısı): Java 24 non-LTS bir sürümdür. Üretim ortamlarında uzun vadeli destek isteyen ekipler genellikle LTS sürümleri (Java 17, 21 ve gelecekte 25) tercih eder. Java 24, yeni özellikleri erken denemek ve LTS'ye geçişe hazırlanmak için idealdir.
Genel Bakış — Java 24'ün Ana Temaları
Java 24, birkaç büyük olgunlaşma hattını bir arada taşır:
- Olgunlaşan modern API'ler: Stream Gatherers artık kalıcı/standart (preview değil).
- Performans ve başlatma hızı: Project Leyden'ın ilk somut meyvesi olan Ahead-of-Time (AOT) Class Loading & Linking; G1 için Late Barrier Expansion; deneysel Generational Shenandoah.
- Kriptografi modernizasyonu: Kuantum-dirençli algoritmalar standart kütüphaneye girdi — ML-KEM (anahtar kapsülleme) ve ML-DSA (dijital imza).
- Dil ergonomisi: Flexible Constructor Bodies preview olarak olgunlaşmaya devam ediyor.
- Project Loom & FFM olgunluğu: Sanal iş parçacıkları (virtual threads) ve Foreign Function & Memory API gibi daha önce kalıcılaşmış özelliklerin üzerine inşa.
Aşağıda her özellik tek tek ele alınıyor.
1. Stream Gatherers (JEP 485) — ARTIK KALICI / STANDART
İlgili örnek dosya:
StreamGatherersKalici.java
NEDİR
Stream Gatherers, java.util.stream.Stream arayüzüne eklenen gather(Gatherer) ara
işlemidir (intermediate operation). Collector'ın terminal (sonlandırıcı) işlemler için
yaptığını, Gatherer ara işlemler için yapar: özel, yeniden kullanılabilir, durum
tutabilen (stateful) akış dönüşümleri yazmamıza izin verir.
Gatherer API'si dört bileşenden oluşur:
- initializer — durum (state) nesnesi oluşturur (opsiyonel),
- integrator — her elemanı işler, downstream'e iter, kısa devre (short-circuit) yapabilir,
- combiner — paralel akışlarda durumları birleştirir (opsiyonel),
- finisher — akış bittiğinde kalan elemanları iter (opsiyonel).
NEDEN GELDİ
Standart kütüphanedeki ara işlemler (map, filter, limit, takeWhile...) sınırlıdır.
"Pencereleme (windowing)", "kayan birikim (scan)", "ardışık tekilleştirme", "N'erli gruplama"
gibi yaygın ihtiyaçlar için ya stream'i bırakıp döngü yazmak ya da karmaşık Collector
hileleri yapmak gerekiyordu. Gatherers bu boşluğu doldurur.
NE İŞE YARAR
- Akışı sabit boyutlu pencerelere bölme (
Gatherers.windowFixed(n)). - Kayan pencere (
Gatherers.windowSliding(n)). - Birikimli/kümülatif hesap (
Gatherers.scan(...)) — örn. yürüyen toplam, koşan bakiye. - Eşzamanlı/asenkron eşleme (
Gatherers.mapConcurrent(...)) — sanal iş parçacıklarıyla paralel I/O. - Tamamen özel durum tutan dönüşümler (
Gatherer.ofSequential(...)ile).
NEREDE KOLAYLIK SAĞLAR
Veri akışı işleme (batch'leme), gerçek zamanlı telemetri/IoT verisi gruplama, finansal hesaplamalar (koşan bakiye), log işleme, ETL pipeline'ları. Akış zincirini bozmadan, okunabilir ve birleştirilebilir kalmasını sağlar.
ESKİ vs YENİ
Eski (Java 23 ve öncesi — preview veya manuel döngü):
// N'erli batch'leme için elle döngü List<List<Order>> batches = new ArrayList<>(); List<Order> current = new ArrayList<>(); for (Order o : orders) { current.add(o); if (current.size() == 100) { batches.add(current); current = new ArrayList<>(); } } if (!current.isEmpty()) batches.add(current);
Yeni (Java 24 — kalıcı, preview bayrağı YOK):
List<List<Order>> batches = orders.stream() .gather(Gatherers.windowFixed(100)) .toList();
GERÇEK HAYAT ÖRNEĞİ
Bir ödeme sisteminde gelen işlemleri 100'erli paketler halinde toplu API'ye gönderme
(windowFixed), bir hesabın işlem geçmişinden koşan bakiye üretme (scan), sensör
verisinden hareketli ortalama hesaplama (windowSliding). Detaylar
StreamGatherersKalici.java içindedir.
ÖNEMLİ: Preview bayrağı artık gerekmiyor
Java 22 ve 23'te Gatherers preview idi ve --enable-preview ile derlenip çalıştırılması
gerekiyordu. Java 24'te kalıcılaştı: standart derleme/çalıştırma yeterli.
javac StreamGatherersKalici.java # --enable-preview YOK java StreamGatherersKalici
2. Class-File API (JEP 484) — STANDART
İlgili not dosyası:
ClassFileApiNotlari.md
NEDİR
.class dosyalarını (Java bytecode) okumak, yazmak ve dönüştürmek için JDK'nın
standart, resmi API'sidir (java.lang.classfile paketi). JEP 484 ile kalıcılaştı.
NEDEN GELDİ
JDK'nın kendi içinde, bytecode üretmek/işlemek için gömülü (shaded) bir ASM kopyası taşınıyordu. Bu kopya, yeni class dosyası formatı sürümlerinin gerisinde kalabiliyor ve bakım yükü yaratıyordu. Standart bir API, JDK'nın iç ASM bağımlılığını ortadan kaldırır ve class dosyası formatıyla her zaman senkron kalır.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR
- Bytecode üretimi (framework'ler, ORM proxy'leri, derleyiciler).
- Java agent'ları ve enstrümantasyon (instrumentation) araçları.
- Statik analiz, bytecode dönüşümü/optimizasyonu.
- Dış ASM/Javassist gibi kütüphane bağımlılığı olmadan, JDK ile gelen API'yi kullanabilme.
ESKİ vs YENİ
- Eski: ASM, Javassist, BCEL gibi 3. parti kütüphaneler veya yansıma (reflection).
- Yeni: JDK'nın yerleşik, değişmez (immutable) ağaç tabanlı modeli; format ile
her zaman uyumlu. Detaylar
ClassFileApiNotlari.md.
3. Ahead-of-Time (AOT) Class Loading & Linking (JEP 483) — Project Leyden Başlangıcı
NEDİR
Uygulamanın daha önceki bir çalıştırmasında gözlemlenen sınıfların yüklenmiş ve bağlanmış (linked) halini bir önbelleğe (AOT cache) kaydedip, sonraki çalıştırmalarda bu hazır durumu yükleyerek başlatmayı hızlandıran mekanizmadır. Project Leyden'ın ilk üretim-kalitesindeki adımıdır.
NEDEN GELDİ
JVM başlangıcının önemli bir kısmı, sınıfların okunması, doğrulanması (verification) ve bağlanmasıyla geçer. Özellikle büyük framework'lerde (Spring vb.) bu maliyet yüksektir. Mikroservis ve serverless dünyasında soğuk başlatma (cold start) süresi kritiktir.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR
- Başlatma süresini kısaltır (özellikle büyük uygulamalarda kayda değer iyileşme).
- Kubernetes/serverless ortamlarında daha hızlı ölçeklenme.
ESKİ vs YENİ (kavramsal)
- Eski: Her başlatmada sınıflar sıfırdan yüklenir/doğrulanır/bağlanır (CDS/AppCDS kısmi yardım sağlıyordu).
- Yeni: Eğitim (training) çalıştırmasıyla bir AOT önbelleği üretilir; sonraki çalıştırmalar bu önbellekten faydalanır.
Dürüst not: AOT cache üretme/kullanma komut satırı bayraklarının tam söz dizimi JDK sürümleri arasında ayarlanıyor olabilir; üretimde kullanmadan önce kurulu JDK'nın resmi belgelerine bakılması önerilir.
4. Generational Shenandoah (Deneysel)
NEDİR
Düşük gecikmeli (low-pause) Shenandoah çöp toplayıcısının (GC) kuşak ayrımlı (generational) sürümüdür. Nesneleri yaşına göre genç/yaşlı kuşaklara ayırır.
NEDEN GELDİ
"Çoğu nesne genç ölür" (weak generational hypothesis) varsayımı, kuşak ayrımı yapan toplayıcıların genellikle daha verimli olmasını sağlar. Shenandoah'a bu yetenek kazandırılarak hem düşük gecikme hem daha iyi verimlilik (throughput) hedeflenir.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR
Tahmin edilebilir, kısa GC duraklamaları isteyen gecikmeye duyarlı sistemlerde (finans, oyun sunucuları, gerçek zamanlı hizmetler) bellek yönetimini iyileştirir.
Durum: Bu sürümde deneyseldir; üretimde dikkatli değerlendirilmelidir. Etkinleştirme için ilgili
-XXdeneysel bayrakları gerekir.
5. Quantum-Resistant Kriptografi: ML-KEM (JEP 496) & ML-DSA (JEP 497)
İlgili not dosyası:
KuantumDirencliKripto.md
NEDİR
- ML-KEM (JEP 496): Module-Lattice tabanlı Anahtar Kapsülleme Mekanizması (Key Encapsulation Mechanism). NIST'in FIPS 203 standardı (CRYSTALS-Kyber tabanlı).
- ML-DSA (JEP 497): Module-Lattice tabanlı Dijital İmza Algoritması. NIST'in FIPS 204 standardı (CRYSTALS-Dilithium tabanlı).
NEDEN GELDİ
Yeterince güçlü bir kuantum bilgisayar, Shor algoritması ile RSA ve ECC gibi klasik açık anahtarlı şemaları kırabilir. "Harvest now, decrypt later" (şimdi topla, sonra çöz) tehdidi nedeniyle bugün şifrelenen veriler gelecekte risk altındadır. Bu yüzden kuantum-dirençli (post-quantum) algoritmaların bugünden standart kütüphaneye girmesi gerekiyordu.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR
TLS, VPN, güvenli mesajlaşma, yazılım imzalama, uzun ömürlü gizli veriler. Detaylar ve
kavramsal API örnekleri KuantumDirencliKripto.md içinde.
ESKİ vs YENİ
- Eski: RSA / ECC / ECDSA — kuantum bilgisayara karşı kırılgan.
- Yeni: ML-KEM ve ML-DSA — kafes (lattice) problemlerinin zorluğuna dayanır, kuantuma dirençlidir.
6. Flexible Constructor Bodies (JEP 492 — Üçüncü Preview)
NEDİR
Bir kurucu metotta (constructor), super(...) veya this(...) çağrısından ÖNCE
ifade çalıştırmaya (örn. argüman doğrulama, alanların erken ilklendirilmesi) izin verir.
NEDEN GELDİ
Klasik Java kuralında super(...)/this(...) çağrısı kurucunun ilk ifadesi olmak
zorundaydı. Bu, argümanları üst sınıfa göndermeden önce doğrulamayı veya hazırlamayı
zorlaştırıyordu (çoğunlukla yardımcı statik metotlarla dolanılıyordu).
ESKİ vs YENİ
// ESKİ: doğrulama için statik yardımcı metot hilesi public Hesap(BigDecimal bakiye) { super(dogrula(bakiye)); } private static BigDecimal dogrula(BigDecimal b) { /* ... */ return b; } // YENİ (preview): super'den önce doğrulama public Hesap(BigDecimal bakiye) { if (bakiye.signum() < 0) throw new IllegalArgumentException("Negatif bakiye olamaz"); super(bakiye); }
Durum: Bu sürümde hâlâ preview'dır (
--enable-previewgerekir). Kalıcılaşma yolundadır ancak henüz standart değildir.
7. Late Barrier Expansion for G1 (JEP 475)
NEDİR
G1 çöp toplayıcısının kullandığı GC bariyerlerinin (write barrier kodu) JIT derleme hattında daha geç bir aşamada üretilmesini sağlayan bir iç (internal) iyileştirmedir.
NEDEN GELDİ
Bariyerler derleme hattının erken aşamalarında genişletilince, C2 JIT derleyicisinin işi artıyor ve derleme süresi/karmaşıklığı yükseliyordu. Bariyerleri geç genişletmek derleyici yükünü azaltır.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR
Geliştiriciler için şeffaftır — kod değişikliği gerektirmez. JIT derleme süresini ve C2'nin bakım karmaşıklığını azaltır; G1 kullanan tüm uygulamalar dolaylı fayda görür.
Dosya Referansları
| Dosya | İçerik |
|---|---|
README.md | Bu genel bakış dokümanı |
StreamGatherersKalici.java | Çalışan, derlenebilir Gatherers örnekleri |
ClassFileApiNotlari.md | Class-File API notları ve ASM karşılaştırması |
KuantumDirencliKripto.md | ML-KEM / ML-DSA notları, PQC karşılaştırması |
Avantajlar / Dezavantajlar / Riskler
Avantajlar
- Stream Gatherers kalıcı: Preview bayrağı olmadan, üretimde güvenle kullanılabilir.
- Class-File API standart: Dış ASM bağımlılığı olmadan bytecode işleme.
- Kuantum-dirençli kripto standart kütüphanede: PQC'ye geçiş için sağlam temel.
- Başlatma hızı (AOT): Soğuk başlatma maliyetini düşürür.
- Şeffaf performans iyileştirmeleri: Late Barrier Expansion gibi değişiklikler kod değişikliği gerektirmez.
Dezavantajlar / Riskler
- Non-LTS: Uzun vadeli destek yok; üretim için LTS (17/21/25) genelde daha güvenli.
- Deneysel özellikler: Generational Shenandoah deneyseldir; davranışı değişebilir.
- Preview özellikler: Flexible Constructor Bodies hâlâ preview; API değişebilir,
--enable-previewgerekir, üretimde tavsiye edilmez. - PQC olgunluk: Post-quantum algoritmalar yeni standartlaştı; ekosistem (kütüphane, donanım, birlikte çalışabilirlik) hâlâ olgunlaşıyor. Genellikle hibrit (klasik+PQC) yaklaşım önerilir.
- AOT cache bakımı: Eğitim çalıştırması ve önbellek yönetimi ek operasyonel adım getirir.
Bu doküman eğitim amaçlıdır. JEP detaylarının ve komut satırı bayraklarının kesin hâli için kurulu JDK 24'ün resmi OpenJDK belgeleri esas alınmalıdır.
▶ Kod Örnekleri(1)
StreamGatherersKalici
ortam gerekir1import java.util.ArrayList;
2import java.util.List;
3import java.util.Optional;
4import java.util.stream.Gatherer;
5import java.util.stream.Gatherers;
6import java.util.stream.Stream;
7
8/**
9 * ============================================================================
10 * Java 24 - Stream Gatherers (JEP 485) ARTIK KALICI / STANDART
11 * ============================================================================
12 *
13 * ONEMLI: Java 22 ve 23'te Stream Gatherers "preview" idi ve derleme/calistirma
14 * icin "--enable-preview" bayragi GEREKIYORDU. JAVA 24 ile KALICILASTI:
15 *
16 * javac StreamGatherersKalici.java // --enable-preview YOK !
17 * java StreamGatherersKalici // --enable-preview YOK !
18 *
19 * Gatherer NEDIR?
20 * --------------
21 * Collector terminal (sonlandirici) islemler icin ne yapiyorsa, Gatherer da
22 * ARA (intermediate) islemler icin onu yapar. stream.gather(...) ile cagrilir.
23 * Durum tutabilir (stateful), kisa devre (short-circuit) yapabilir, paralel
24 * calisabilir ve tamamen ozellestirilebilir.
25 *
26 * Gatherer'in 4 bileseni:
27 * - initializer : durum (state) nesnesi olusturur (opsiyonel)
28 * - integrator : her elemani isler, downstream'e iter, kisa devre yapabilir
29 * - combiner : paralel akista durumlari birlestirir (opsiyonel)
30 * - finisher : akis bitince kalan elemanlari iter (opsiyonel)
31 *
32 * Bu dosya gercek hayat senaryolariyla 5 ornek icerir.
33 * ============================================================================
34 */
35public class StreamGatherersKalici {
36
37 public static void main(String[] args) {
38 System.out.println("=== Java 24 Stream Gatherers (KALICI - preview degil) ===\n");
39
40 ornek1_windowFixedBatchIsleme();
41 ornek2_windowSlidingHareketliOrtalama();
42 ornek3_scanKosanBakiye();
43 ornek4_ozelGathererArdisikTekillestirme();
44 ornek5_ozelGathererKisaDevreIlkNTaneEsiktenBuyuk();
45 }
46
47 // ------------------------------------------------------------------------
48 // ORNEK 1: windowFixed -> Gercek hayat: gelen odeme islemlerini 100'erli
49 // (burada 3'erli) paketler halinde toplu API'ye gondermek icin
50 // sabit boyutlu pencerelere bolme (batch'leme).
51 // ------------------------------------------------------------------------
52 static void ornek1_windowFixedBatchIsleme() {
53 System.out.println("--- ORNEK 1: windowFixed (toplu / batch islem) ---");
54
55 // Diyelim ki gercek zamanli olarak gelen 8 odeme islemi var.
56 List<String> odemeler = List.of(
57 "ODM-001", "ODM-002", "ODM-003",
58 "ODM-004", "ODM-005", "ODM-006",
59 "ODM-007", "ODM-008"
60 );
61
62 // Bunlari 3'erli gruplar halinde paketleyip her grubu toplu gonderelim.
63 List<List<String>> paketler = odemeler.stream()
64 .gather(Gatherers.windowFixed(3)) // sabit boyutlu pencere
65 .toList();
66
67 int paketNo = 1;
68 for (List<String> paket : paketler) {
69 // Gercekte burada: toplaApiyeGonder(paket);
70 System.out.println(" Paket #" + (paketNo++) + " gonderiliyor -> " + paket);
71 }
72 System.out.println();
73 }
74
75 // ------------------------------------------------------------------------
76 // ORNEK 2: windowSliding -> Gercek hayat: sensor/telemetri verisinden
77 // kayan pencere ile HAREKETLI ORTALAMA hesaplama.
78 // ------------------------------------------------------------------------
79 static void ornek2_windowSlidingHareketliOrtalama() {
80 System.out.println("--- ORNEK 2: windowSliding (hareketli ortalama) ---");
81
82 // Sicaklik sensorunden gelen olcumler.
83 List<Integer> olcumler = List.of(20, 22, 21, 25, 30, 28, 26);
84
85 // 3'lu kayan pencere ile her pencerenin ortalamasini al.
86 List<Double> hareketliOrtalama = olcumler.stream()
87 .gather(Gatherers.windowSliding(3)) // 3 elemanli kayan pencere
88 .map(pencere -> pencere.stream()
89 .mapToInt(Integer::intValue)
90 .average()
91 .orElse(0.0))
92 .toList();
93
94 System.out.println(" Olcumler : " + olcumler);
95 System.out.println(" 3'lu hareketli ort: " + hareketliOrtalama);
96 System.out.println();
97 }
98
99 // ------------------------------------------------------------------------
100 // ORNEK 3: scan -> Gercek hayat: bir hesabin islem listesinden KOSAN BAKIYE
101 // (running balance) uretme. scan, kumulatif/birikimli hesaptir.
102 // ------------------------------------------------------------------------
103 static void ornek3_scanKosanBakiye() {
104 System.out.println("--- ORNEK 3: scan (kosan/birikimli bakiye) ---");
105
106 // Pozitif = para yatirma, Negatif = para cekme.
107 List<Integer> hareketler = List.of(100, -30, 50, -20, -10);
108
109 // scan: baslangic degeri 0, her adimda yeni bakiye = onceki + hareket.
110 List<Integer> kosanBakiye = hareketler.stream()
111 .gather(Gatherers.scan(() -> 0, (bakiye, hareket) -> bakiye + hareket))
112 .toList();
113
114 System.out.println(" Hareketler : " + hareketler);
115 System.out.println(" Kosan bakiye: " + kosanBakiye);
116 System.out.println();
117 }
118
119 // ------------------------------------------------------------------------
120 // ORNEK 4: OZEL Gatherer -> Ardisik (consecutive) tekrarlari teklestirme.
121 // Yani sadece bir onceki elemanla ayni olani atla.
122 // ("distinct" tum akista benzersiz yaparken, bu sadece ARDISIK
123 // tekrarlari kaldirir.)
124 //
125 // Gatherer.ofSequential ile durum tutan ozel bir ara islem yazariz.
126 // ------------------------------------------------------------------------
127 static void ornek4_ozelGathererArdisikTekillestirme() {
128 System.out.println("--- ORNEK 4: ozel Gatherer (ardisik tekillestirme) ---");
129
130 List<String> girdi = List.of("A", "A", "B", "B", "B", "A", "C", "C");
131
132 List<String> sonuc = girdi.stream()
133 .gather(ardisikTekilGatherer())
134 .toList();
135
136 System.out.println(" Girdi : " + girdi);
137 System.out.println(" Sonuc : " + sonuc);
138 System.out.println();
139 }
140
141 /**
142 * Ardisik tekrarlari eleyen ozel Gatherer.
143 * Durum: bir onceki gorulen eleman (mutable kutu olarak Object[]).
144 */
145 static <T> Gatherer<T, ?, T> ardisikTekilGatherer() {
146 return Gatherer.<T, Object[], T>ofSequential(
147 // initializer: durum nesnesi - tek elemanli dizi (mutable kutu)
148 () -> new Object[]{null, Boolean.FALSE}, // [0]=onceki, [1]=baslatildi mi
149 // integrator: her elemani isle
150 Gatherer.Integrator.ofGreedy((state, eleman, downstream) -> {
151 boolean baslatildi = (Boolean) state[1];
152 Object onceki = state[0];
153 if (!baslatildi || !java.util.Objects.equals(onceki, eleman)) {
154 state[0] = eleman;
155 state[1] = Boolean.TRUE;
156 return downstream.push(eleman); // downstream'e ilet
157 }
158 return true; // ardisik tekrar -> atla, akisa devam
159 })
160 );
161 }
162
163 // ------------------------------------------------------------------------
164 // ORNEK 5: OZEL Gatherer + KISA DEVRE -> Esik degerin uzerindeki ilk N
165 // elemani bulunca akisi durdurma (short-circuit).
166 // Gercek hayat: bir log akisinda ilk 2 "kritik" olayi yakalayinca
167 // islemeyi durdurmak (gereksiz veriyi taramamak).
168 // ------------------------------------------------------------------------
169 static void ornek5_ozelGathererKisaDevreIlkNTaneEsiktenBuyuk() {
170 System.out.println("--- ORNEK 5: ozel Gatherer + kisa devre (ilk N kritik) ---");
171
172 // Cok buyuk/sonsuz bir akisi simule edelim.
173 Stream<Integer> sonsuzAkis = Stream.iterate(1, n -> n + 1);
174
175 int esik = 50;
176 int kacTane = 2;
177
178 List<Integer> ilkKritikler = sonsuzAkis
179 .gather(ilkNTaneEsiktenBuyukGatherer(esik, kacTane))
180 .toList();
181
182 System.out.println(" Esik=" + esik + ", istenen adet=" + kacTane);
183 System.out.println(" Bulunanlar: " + ilkKritikler
184 + " (akis erken durduruldu -> sonsuz akista bile takilmadi)");
185 System.out.println();
186 }
187
188 /**
189 * Esik degerinden buyuk ilk "limit" adet elemani gecirir, sonra akisi keser.
190 * Kisa devre: integrator false donerse akis durur.
191 */
192 static Gatherer<Integer, ?, Integer> ilkNTaneEsiktenBuyukGatherer(int esik, int limit) {
193 return Gatherer.<Integer, int[], Integer>ofSequential(
194 () -> new int[]{0}, // durum: kac tane gecirdik
195 (state, eleman, downstream) -> {
196 if (eleman > esik) {
197 boolean devam = downstream.push(eleman);
198 state[0]++;
199 if (state[0] >= limit) {
200 return false; // YETERLI -> kisa devre, akisi durdur
201 }
202 return devam;
203 }
204 return true; // esigin altinda -> atla, devam et
205 }
206 );
207 }
208
209 // ------------------------------------------------------------------------
210 // Yardimci: Optional ornegi sustur (kullanilmiyor ama import temizligi icin)
211 // ------------------------------------------------------------------------
212 @SuppressWarnings("unused")
213 private static Optional<String> kullanilmayan() {
214 return Optional.empty();
215 }
216
217 // not: ArrayList importu, ileride genisletme/elle ornek icin korunuyor
218 @SuppressWarnings("unused")
219 private static List<String> bos() {
220 return new ArrayList<>();
221 }
222}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.