Eğitim Portalı/Sürüm Analizi/Java 24 — Detaylı Sürüm Analizi (Türkçe)
Sürüm Analizi05-java-versiyon-analizi/17-Java-24

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

ÖzellikDeğer
SürümJava 24 (JDK 24)
Çıkış TarihiMart 2025
Destek TipiNon-LTS (özellik sürümü) — bir sonraki LTS Java 25'tir (Eylül 2025)
Geliştirme süreciOpenJDK, 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:

  1. Olgunlaşan modern API'ler: Stream Gatherers artık kalıcı/standart (preview değil).
  2. 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.
  3. Kriptografi modernizasyonu: Kuantum-dirençli algoritmalar standart kütüphaneye girdi — ML-KEM (anahtar kapsülleme) ve ML-DSA (dijital imza).
  4. Dil ergonomisi: Flexible Constructor Bodies preview olarak olgunlaşmaya devam ediyor.
  5. 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 -XX deneysel 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-preview gerekir). 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.mdBu genel bakış dokümanı
StreamGatherersKalici.javaÇalışan, derlenebilir Gatherers örnekleri
ClassFileApiNotlari.mdClass-File API notları ve ASM karşılaştırması
KuantumDirencliKripto.mdML-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-preview gerekir, ü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 gerekir
StreamGatherersKalici.java
1import 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}
canlı çalıştırma için ortam gerekir

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.