Eğitim Portalı/Sürüm Analizi/Java 21 (Eylül 2023) — LTS — YENİ KURUMSAL STANDART
Sürüm Analizi05-java-versiyon-analizi/14-Java-21

Java 21 (Eylül 2023) — LTS — YENİ KURUMSAL STANDART

| Özellik | Değer | |---|---| | Sürüm | Java 21 (JDK 21) | | Çıkış Tarihi | 19 Eylül 2023 | | Destek Türü | LTS (Long-Term Support) — UZUN VADELİ DESTEK | | LTS mı? | EVET. Java 8, 11, 17'den sonraki en yeni LTS. | |…

Java 21 (Eylül 2023) — LTS — YENİ KURUMSAL STANDART

Sürüm Bilgileri

ÖzellikDeğer
SürümJava 21 (JDK 21)
Çıkış Tarihi19 Eylül 2023
Destek TürüLTS (Long-Term Support) — UZUN VADELİ DESTEK
LTS mı?EVET. Java 8, 11, 17'den sonraki en yeni LTS.
Destek SüresiTipik olarak 8+ yıl (sağlayıcıya göre genişletilmiş destek dahil)
Önceki LTSJava 17 (Eylül 2021)
Sonraki LTSJava 25 (Eylül 2025)
JEP Sayısı15 JEP

NEDEN JAVA 21 YENİ KURUMSAL STANDART? (GÜÇLÜ VURGU)

Java 21, sadece bir başka sürüm değil; 2024-2028 arası kurumsal Java'nın yeni temel hattıdır. İşte nedenleri:

1. LTS = Uzun Vadeli Destek

Kurumlar üretim sistemlerini ara (feature) sürümlere kuramaz; çünkü onların desteği yalnızca 6 ay sürer. Java 21 LTS, yıllarca güvenlik yaması ve destek alacaktır. Java 8 ve Java 11'den göç eden devasa kod tabanlarının hedefi artık Java 21'dir (Java 17 yerine bile doğrudan 21 tercih edilmektedir, çünkü 21 daha fazla olgun özellik içerir).

2. Virtual Threads (Project Loom) KALICI

Bu, son 20 yılın en büyük JVM eşzamanlılık devrimidir. Yıllardır preview'de olan virtual threads ilk kez Java 21'de kalıcı oldu. Bu, sunucu tarafı Java'yı yeniden tanımlar: basit, bloklayıcı kod yazarak milyonlarca eşzamanlı bağlantıyı kaldırabilirsiniz. Reaktif programlamanın (Reactor, RxJava) karmaşıklığına çoğu senaryoda artık gerek kalmaz.

3. Modern Dil Özellikleri Olgunlaştı

Pattern Matching for switch ve Record Patterns kalıcı oldu. Bu ikisi birlikte, Java'ya fonksiyonel ve veri-odaklı (data-oriented) programlamanın gücünü kazandırır.

4. Sequenced Collections

20+ yıllık bir API boşluğu (koleksiyonun ilk/son elemanına tutarlı erişim) nihayet kapandı.

5. Generational ZGC

Çok düşük gecikmeli (sub-millisecond pause) çöp toplayıcı, nesil-bazlı (generational) hale gelerek verimlilik kazandı. Büyük heap'li, gecikmeye duyarlı sistemler için ideal.

Özet: Java 17'den Java 21'e geçiş, modern bir Java ekibi için artık bir tercih değil, bir hedeftir. Virtual Threads tek başına bu geçişi haklı çıkaracak kadar değerlidir.


Genel Bakış — Java 21 Özellikleri

KALICI (Final) Özellikler

  1. JEP 444 — Virtual Threads — Project Loom. EN ÖNEMLİSİ.
  2. JEP 441 — Pattern Matching for switch — Desen eşleştirme kalıcı.
  3. JEP 440 — Record Patterns — İç içe yıkım (destructuring) kalıcı.
  4. JEP 431 — Sequenced Collections — Sıralı koleksiyon arayüzleri.
  5. JEP 439 — Generational ZGC — Nesil-bazlı düşük gecikmeli GC.

PREVIEW / INCUBATOR Özellikler

  1. JEP 430 — String Templates (1. Preview) — Güvenli string interpolasyonu.
  2. JEP 443 — Unnamed Patterns and Variables (Preview) — _ ile isimsiz desen/değişken.
  3. JEP 445 — Unnamed Classes and Instance Main Methods (Preview) — Yeni başlayanlar için basit main.
  4. JEP 453 — Structured Concurrency (Preview).
  5. JEP 446 — Scoped Values (Preview).

Özellik Detayları

1. Virtual Threads (JEP 444) — KALICI — Project Loom — EN ÖNEMLİSİ

İlgili dosya: VirtualThreadsKalici.java

NEDİR?

Virtual thread, JVM tarafından yönetilen çok hafif bir iş parçacığıdır. Geleneksel platform thread'in (OS thread'inin 1:1 sarmalayıcısı) aksine, virtual thread'ler az sayıda OS thread'i (taşıyıcı / carrier thread) üzerinde çoklanır. Milyonlarca virtual thread tek bir JVM'de var olabilir.

NEDEN GELDİ? (DERİNLEMESİNE)

Problem 1 — Platform thread'ler pahalıdır: Her platform thread bir OS thread'idir; ~1 MB stack tüketir ve OS tarafından zamanlanır. Bir sunucu pratikte birkaç bin platform thread'i aşamaz. 10.000 eşzamanlı kullanıcı = imkansız.

Problem 2 — Thread-per-request modeli ölçeklenmiyor: Java sunucularının klasik ve en okunabilir modeli "her istek için bir thread" idi. Kod basit ve senkrondur:

String veri = veritabaniSorgula();   // blokla
String sonuc = baskaServisCagir(veri); // blokla
yanitDon(sonuc);

Ama her bloklamada pahalı OS thread'i boşta bekler. Birkaç bin eşzamanlı istekte thread'ler tükenir; sistem yeni istek alamaz. Oysa CPU boştadır — darboğaz thread sayısıdır, işlemci değil.

Problem 3 — Reaktif programlama karmaşıktır: Sektör bu duvarı aşmak için reaktif/asenkron modellere (CompletableFuture, Reactor, RxJava) yöneldi. Bunlar az sayıda thread'le çok iş yapar AMA:

  • Kod callback/operatör zincirlerine döner; okunması zordur.
  • Stack trace'ler anlamsızlaşır; hata ayıklama kabusa döner.
  • try/catch, döngü, debugger gibi temel araçlar düzgün çalışmaz.
  • "Renk problemi" (function coloring): asenkron fonksiyonlar her şeyi asenkron olmaya zorlar.

Virtual Threads bu ikilemi ortadan kaldırır: Basit, senkron, bloklayıcı kod yazarsınız (okunabilirlik) ama reaktif sistemler kadar ölçeklenir (performans). İki dünyanın en iyisi.

NASIL ÇALIŞIR? (mount / unmount, carrier thread)

  1. Bir virtual thread çalışmak için bir carrier thread'e (platform thread) bindirilir (mount).
  2. Virtual thread bloklayıcı bir işleme girerse (örn. socket.read(), Thread.sleep, JDBC çağrısı), JVM virtual thread'in durumunu (stack) heap'e kaydeder ve onu carrier'dan söker (unmount).
  3. Boşalan carrier thread hemen başka bir virtual thread'i çalıştırmaya başlar.
  4. Bloklayıcı işlem tamamlandığında, virtual thread tekrar (herhangi bir) carrier'a bindirilir ve kaldığı yerden devam eder.

Sonuç: OS thread'leri asla boşta beklemez; her zaman gerçek iş yaparlar. Bloklanan iş, ucuz heap belleğinde "park" eder. Bu yüzden birkaç düzine carrier thread, milyonlarca virtual thread'e hizmet edebilir.

Pinning (sabitlenme) uyarısı: synchronized blok içinde bloklanan veya yerel (native) çağrı yapan virtual thread carrier'dan sökülemez ("pinned" olur). Bu, ölçeklenmeyi bozabilir. Çözüm: synchronized yerine ReentrantLock kullanın. (Java 24 ile pinning büyük ölçüde giderildi.)

GERÇEK KAZANIM

  • Platform thread: ~birkaç bin eşzamanlı bağlantı tavanı.
  • Virtual thread: milyonlarca eşzamanlı bağlantı, aynı donanımda.
  • Kod ise eskisi gibi basit ve senkron kalır.

ESKİ vs YENİ

// ESKİ — sabit boyutlu havuz, thread sayısı darboğaz
ExecutorService es = Executors.newFixedThreadPool(200);
// 201. eşzamanlı uzun istek kuyruğa girer

// YENİ (Java 21, KALICI) — her görev için bir virtual thread
try (var es = Executors.newVirtualThreadPerTaskExecutor()) {
    es.submit(() -> { ... });  // milyonlarca olabilir
}

GERÇEK HAYAT ÖRNEĞİ — Web Sunucu / Mikroservis

Bir mikroservis her isteği işlerken 3 ayrı servise (kullanıcı, envanter, fiyat) bloklayıcı HTTP çağrısı yapar; her çağrı ~100 ms sürer. Yani her istek ~300 ms'nin çoğunu beklemeyle geçirir.

  • Platform thread (havuz 200): Aynı anda en fazla ~200 istek; daha fazlası kuyrukta bekler. Bekleme sırasında 200 pahalı OS thread'i boşta durur. Throughput düşük.
  • Virtual thread: 50.000 istek aynı anda gelebilir; her biri kendi virtual thread'inde bloklanır, OS thread'leri bu sırada başka istekleri işler. Aynı donanımda çok daha yüksek throughput.

Spring Boot 3.2+, Tomcat, Helidon, Quarkus gibi framework'ler bir bayrakla virtual thread'leri etkinleştirir. Çoğu zaman kodu değiştirmeden ölçeklenirsiniz.

STRUCTURED CONCURRENCY İLE İLİŞKİSİ

Virtual thread'ler ucuz olduğundan, bir isteğin alt görevlerini (yukarıdaki 3 servis çağrısı) ayrı virtual thread'lerde paralel çalıştırmak doğaldır. Structured Concurrency (JEP 453) bu alt görevleri tek bir iş birimi gibi yönetir: birlikte başlar, biri patlarsa diğerleri otomatik iptal olur. Bu üçlü (virtual threads + structured concurrency + scoped values) modern Java sunucu mimarisinin temelidir.

AVANTAJ / DEZAVANTAJ / RİSK

  • Avantaj: Basit kod + devasa ölçeklenme; reaktif karmaşıklığa veda.
  • Dezavantaj/Risk: CPU-yoğun (hesaplama ağırlıklı) işler için fayda sağlamaz — onlar zaten thread'i meşgul eder. synchronized ile pinning riski. Havuzlama (pooling) ANTI-PATTERN'dir: virtual thread'leri havuzlamayın, her görev için yenisini açın.

2. Pattern Matching for switch (JEP 441) — KALICI

İlgili dosya: PatternMatchingSwitchKalici.java

NEDİR?

switch içinde tür desenleri (type patterns), guarded patterns (when), null işleme ve sealed hiyerarşilerle tamlık (exhaustiveness) kontrolü.

NEDEN GELDİ?

Uzun if-else instanceof zincirleri okunması zor ve hataya açıktı. Veri-odaklı kod (bir nesnenin türüne göre dallanma) için ifade gücü gerekiyordu.

ESKİ vs YENİ

// ESKİ
String aciklama;
if (o instanceof Integer i && i > 0) aciklama = "pozitif: " + i;
else if (o instanceof String s) aciklama = "metin: " + s;
else if (o == null) aciklama = "bos";
else aciklama = "diger";

// YENİ (KALICI)
String aciklama = switch (o) {
    case null            -> "bos";
    case Integer i when i > 0 -> "pozitif: " + i;
    case Integer i       -> "pozitif olmayan: " + i;
    case String s        -> "metin: " + s;
    default              -> "diger";
};

EVRİM

Java 17 (1.) -> 18 (2.) -> 19 (3.) -> 20 (4.) -> 21 (KALICI)


3. Record Patterns (JEP 440) — KALICI

İlgili dosya: RecordPatternsKalici.java

NEDİR?

Record'ları eşleştirirken bileşenlerini doğrudan değişkenlere yıkma (destructuring) — özellikle iç içe (nested) yıkım.

ESKİ vs YENİ

record Adres(String sehir, String ulke) {}
record Kullanici(String ad, Adres adres) {}

// ESKİ
if (o instanceof Kullanici k) {
    String sehir = k.adres().sehir();
    ...
}

// YENİ (KALICI) — iç içe yıkım
if (o instanceof Kullanici(String ad, Adres(String sehir, String ulke))) {
    // ad, sehir, ulke doğrudan kullanılabilir
}

EVRİM

Java 19 (1.) -> 20 (2.) -> 21 (KALICI)


4. Sequenced Collections (JEP 431) — KALICI

İlgili dosya: SequencedCollections.java

NEDİR?

Üç yeni arayüz: SequencedCollection, SequencedSet, SequencedMap. Bunlar, tanımlı bir karşılaşma sırası (encounter order) olan koleksiyonlara ilk/son elemana tutarlı erişim ve ters çevirme yetenekleri kazandırır:

  • getFirst(), getLast()
  • addFirst(e), addLast(e)
  • removeFirst(), removeLast()
  • reversed() — ters sıralı bir görünüm (view)

NEDEN GELDİ?

20+ yıllık bir tutarsızlık vardı:

  • List'in ilk elemanı: list.get(0)
  • Deque'in ilk elemanı: deque.getFirst()
  • LinkedHashSet'in ilk elemanı: ??? — iterator().next() ile uğraşmak gerekiyordu
  • Son eleman almak için List'te list.get(list.size()-1), başka koleksiyonlarda başka yollar.

Sıralı tüm koleksiyonlar için ortak ve tutarlı bir API yoktu.

ESKİ vs YENİ

// ESKİ — her tür için farklı, çirkin
String ilk = list.get(0);
String son = list.get(list.size() - 1);
String ilkSet = linkedHashSet.iterator().next(); // son eleman çok zor!

// YENİ (KALICI) — her sıralı koleksiyonda aynı
String ilk = list.getFirst();
String son = list.getLast();
List<String> ters = list.reversed();

GERÇEK HAYAT ÖRNEĞİ

Bir "son görüntülenen ürünler" listesi (LinkedHashSet, eklenme sırasını korur). En son ve en eski görüntülenen ürüne erişim artık tek satır: set.getLast() / set.getFirst().


5. Generational ZGC (JEP 439) — KALICI

NEDİR?

ZGC (Z Garbage Collector), milisaniye altı duraklama (pause) süreleriyle bilinen düşük gecikmeli bir çöp toplayıcıdır. Java 21 ile nesil-bazlı (generational) hale geldi: nesneleri "genç" ve "yaşlı" nesillere ayırır.

NEDEN GELDİ?

"Çoğu nesne genç ölür" (weak generational hypothesis) gözlemine göre, genç nesilleri sık ve ucuza toplamak çok daha verimlidir. Eski (non-generational) ZGC bu avantajı kullanmıyordu.

NEREDE KOLAYLIK SAĞLAR?

Büyük heap'li (onlarca/yüzlerce GB), gecikmeye duyarlı sistemler (finansal işlem, gerçek zamanlı analitik, büyük web servisleri) için daha az CPU ve bellek ile aynı düşük gecikme.

KULLANIM

# Java 21'de Generational ZGC'yi etkinleştir
java -XX:+UseZGC -XX:+ZGenerational UygulamaSinifi
# (Java 23+ ile generational mod varsayılan oldu)

6. String Templates (JEP 430) — 1. PREVIEW

İlgili dosya: StringTemplatesPreview.java

NEDİR?

Güvenli ve okunabilir string interpolasyonu. STR."Merhaba \{isim}" gibi gömülü ifadelerle string oluşturma. Sadece birleştirme değil; SQL/HTML gibi bağlamlarda kaçış (escaping) ve doğrulama yapabilen şablon işlemcileri (template processors) de sunar.

NEDEN GELDİ?

+ ile birleştirme dağınık, String.format hataya açık (argüman sırası), ve hiçbiri enjeksiyon güvenliği sağlamıyordu (SQL injection, XSS).

ESKİ vs YENİ

String isim = "Ayşe"; int yas = 30;

// ESKİ
String s1 = "Ad: " + isim + ", Yaş: " + yas;
String s2 = String.format("Ad: %s, Yaş: %d", isim, yas);

// YENİ (preview)
String s3 = STR."Ad: \{isim}, Yaş: \{yas}";

NOT: String Templates Java 21 ve 22'de preview kaldı; Java 23'te kaldırıldı (geri çekildi) ve yeniden tasarlanmak üzere ertelendi. Bu yüzden üretimde kullanmayın; kavramsal olarak bilin.

EVRİM/RİSK

Java 21 (1. preview) -> 22 (2. preview) -> 23: tasarımdan KALDIRILDI. İleride farklı bir biçimde dönmesi beklenir.


7. Unnamed Patterns and Variables (JEP 443) — PREVIEW

İlgili dosya örnekleri: RecordPatternsKalici.java içinde de gösterilmiştir.

NEDİR?

_ (alt çizgi) ile kullanılmayacak değişken ve desen bileşenlerini isimsiz bırakma. Niyeti açıkça belirtir: "bu değer var ama umurumda değil."

ESKİ vs YENİ

// ESKİ — kullanılmayan değişken yine de isimlendirilmeli
catch (Exception e) { logla(); } // 'e' kullanılmıyor ama isim zorunlu
for (var ignored : liste) sayac++; // anlamsız 'ignored'

// YENİ (preview)
catch (Exception _) { logla(); }
for (var _ : liste) sayac++;
if (o instanceof Nokta(int x, int _)) {...} // y'yi umursamıyoruz

EVRİM

Java 21 (preview) -> Java 22: KALICI (JEP 456).


8. Unnamed Classes and Instance Main Methods (JEP 445) — PREVIEW

İlgili dosya: UnnamedMainMethod.java

NEDİR?

Yeni başlayanların "Merhaba Dünya"yı yazmak için public static void main(String[] args) ve sınıf bildirimi gibi tüm seremoniyi öğrenmesine gerek kalmadan basit main yazabilmesi.

NEDEN GELDİ?

Java'nın öğrenme eğrisindeki ilk engel, basit bir programın bile çok sayıda kavram (sınıf, public, static, void, String[]) gerektirmesiydi. Bu, eğitimde caydırıcıydı.

ESKİ vs YENİ

// ESKİ — tam seremoni
public class Merhaba {
    public static void main(String[] args) {
        System.out.println("Merhaba Dünya");
    }
}

// YENİ (preview) — sınıf gövdesi ve static gerekmez
void main() {
    System.out.println("Merhaba Dünya");
}

EVRİM

Java 21 (preview) -> 22, 23 (gelişen preview'ler) -> Java 25: KALICI (Compact Source Files / Instance Main Methods olarak).


9. Structured Concurrency (JEP 453) — PREVIEW

İlgili dosya: StructuredConcurrency.java

NEDİR?

Eşzamanlı alt görevleri tek bir iş birimi olarak yöneten StructuredTaskScope. Alt görevler birlikte başlar, birlikte tamamlanır/iptal olur. Hata yayılımı ve iptal otomatiktir.

NEDEN GELDİ?

Manuel ExecutorService/Future ile alt görev iptali, hata yayılımı ve sızıntı önleme zordu ("unstructured concurrency"). Virtual thread'lerle birlikte, paralel alt görevleri güvenle yönetmek için yapısal bir model gerekiyordu.

EVRİM

Java 19 (incubator) -> 20 (incubator) -> 21 (preview) -> ... olgunlaşmaya devam.


10. Scoped Values (JEP 446) — PREVIEW

NEDİR?

ThreadLocal'a değişmez, virtual thread dostu alternatif. (Detay: 13-Java-20/ScopedValuesNotlari.md.)

EVRİM

Java 20 (incubator) -> Java 21 (preview, java.lang paketine taşındı).


Geçiş Rehberi: Java 17 LTS -> Java 21 LTS

Çoğu kurum doğrudan bu sıçramayı yapar (17 -> 21). İşte özet:

KonuEtkiAksiyon
Virtual ThreadsKALICI, devrimselFramework bayrağıyla etkinleştir; synchronized -> ReentrantLock gözden geçir; virtual thread'leri havuzlama
Pattern Matching / Record PatternsKALICIif-else instanceof zincirlerini sadeleştir
Sequenced CollectionsKALICIgetFirst/getLast/reversed ile kodu temizle
Generational ZGCKALICIDüşük gecikme isteyen sistemlerde -XX:+UseZGC -XX:+ZGenerational
String TemplatesPREVIEW (sonra kaldırıldı)Üretimde KULLANMA
Unnamed/Instance MainPREVIEWSadece eğitim/deneme
Deprecation/RemovalBazı eski API'ler kaldırıldıjdeprscan ile tarayın

Avantaj / Dezavantaj / Risk (Genel)

  • Avantaj: Uzun destek, devrimsel eşzamanlılık, modern dil, performanslı GC. Yeni kurumsal standart.
  • Risk: Preview özelliklere (String Templates) bağlanmak; synchronized pinning; eski kütüphanelerin Java 21 uyumu.
  • Tavsiye: Java 21'i yeni projeler için varsayılan hedef yapın. Mevcut Java 8/11/17 projelerini buraya taşımayı planlayın.

Bu Klasördeki Çalışan Örnekler

DosyaKonuPreview?
VirtualThreadsKalici.javaPlatform vs virtual thread, binlerce eşzamanlı istekHayır (kalıcı)
PatternMatchingSwitchKalici.javaswitch + tür/guarded/null desenleriHayır (kalıcı)
RecordPatternsKalici.javaİç içe record yıkımı + isimsiz desenHayır (kalıcı; _ kısmı preview)
SequencedCollections.javagetFirst/getLast/reversedHayır (kalıcı)
StringTemplatesPreview.javaSTR şablon işlemcisiEvet (preview)
UnnamedMainMethod.javaBasit instance mainEvet (preview)
StructuredConcurrency.javaStructuredTaskScopeEvet (preview)

Kod Örnekleri(7)

PatternMatchingSwitchKalici

çalıştırılabilir
PatternMatchingSwitchKalici.java
1import java.util.List;
2
3/**
4 * JAVA 21 - PATTERN MATCHING FOR SWITCH (JEP 441) - KALICI
5 * =========================================================
6 *
7 * Bu dosya, switch icinde desen eslestirmeyi (KALICI) gosterir:
8 *   - tur desenleri (type patterns)
9 *   - korumali desenler (guarded patterns: 'when')
10 *   - null'in switch icinde ele alinmasi
11 *   - sealed (muhurlu) hiyerarsi ile tamlik (exhaustiveness)
12 *
13 * EVRIM: Java 17 (1.) -> 18 (2.) -> 19 (3.) -> 20 (4.) -> 21 (KALICI)
14 *
15 * --- DERLEME / CALISTIRMA (KALICI; --enable-preview GEREKMEZ) ---
16 *   javac PatternMatchingSwitchKalici.java
17 *   java  PatternMatchingSwitchKalici
18 */
19public class PatternMatchingSwitchKalici {
20
21    // Veri-odakli (data-oriented) modelleme icin sealed hiyerarsi
22    sealed interface Odeme permits KrediKarti, Havale, Kripto {}
23    record KrediKarti(String numara, double tutar) implements Odeme {}
24    record Havale(String iban, double tutar) implements Odeme {}
25    record Kripto(String cuzdan, double tutar, String birim) implements Odeme {}
26
27    public static void main(String[] args) {
28        System.out.println("=== JAVA 21: PATTERN MATCHING FOR SWITCH (KALICI) ===\n");
29
30        ornek1_turVeGuarded();
31        ornek2_nullIsleme();
32        ornek3_sealedTamlik();
33    }
34
35    /**
36     * Tur desenleri + korumali desenler (when).
37     * Object alip turune ve degerine gore davranir.
38     */
39    static void ornek1_turVeGuarded() {
40        System.out.println("--- Ornek 1: Tur + korumali (when) desenler ---");
41        for (Object o : List.of(42, -7, "Merhaba", 3.14, List.of(1, 2, 3))) {
42            String aciklama = switch (o) {
43                // korumali desen: tur eslesir VE kosul saglanirsa
44                case Integer i when i > 0 -> "pozitif tam sayi: " + i;
45                case Integer i            -> "pozitif olmayan tam sayi: " + i;
46                case String s             -> "metin (" + s.length() + " karakter): " + s;
47                case Double d             -> "ondalik: " + d;
48                default                   -> "diger tur: " + o.getClass().getSimpleName();
49            };
50            System.out.println("  " + aciklama);
51        }
52        System.out.println();
53    }
54
55    /**
56     * null artik switch icinde ACIKCA ele alinabilir (case null).
57     * ESKIDEN switch(null) -> NullPointerException firlatirdi.
58     */
59    static void ornek2_nullIsleme() {
60        System.out.println("--- Ornek 2: null'in switch icinde ele alinmasi ---");
61        for (Object o : java.util.Arrays.asList("dolu", null, 5)) {
62            String sonuc = switch (o) {
63                case null      -> "deger BOS (null)";
64                case String s  -> "metin: " + s;
65                default        -> "diger: " + o;
66            };
67            System.out.println("  " + sonuc);
68        }
69        System.out.println();
70    }
71
72    /**
73     * sealed arayuz + switch -> derleyici TAMLIK (exhaustiveness) garantisi verir.
74     * Tum alt turler kapsandiginda 'default' GEREKMEZ. Yeni bir alt tur eklenirse
75     * derleyici switch'i guncellemeniz icin HATA verir (guvenli evrim).
76     */
77    static void ornek3_sealedTamlik() {
78        System.out.println("--- Ornek 3: sealed hiyerarsi + tamlik (record pattern ile) ---");
79        List<Odeme> odemeler = List.of(
80                new KrediKarti("1234-5678-...", 250.0),
81                new Havale("TR12 0006 ...", 1000.0),
82                new Kripto("0xABCD...", 0.05, "BTC")
83        );
84
85        for (Odeme odeme : odemeler) {
86            // record pattern + switch: tur eslesir, alanlar yikilir, 'default' yok
87            String mesaj = switch (odeme) {
88                case KrediKarti(String numara, double tutar) ->
89                        "Kredi karti odemesi: " + tutar + " TL (kart: " + numara + ")";
90                case Havale(String iban, double tutar) ->
91                        "Havale: " + tutar + " TL (IBAN: " + iban + ")";
92                case Kripto(String cuzdan, double tutar, String birim) ->
93                        "Kripto: " + tutar + " " + birim + " (cuzdan: " + cuzdan + ")";
94                // sealed + tum alt turler kapsandi -> default GEREKMEZ
95            };
96            System.out.println("  " + mesaj);
97        }
98        System.out.println();
99    }
100}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

RecordPatternsKalici

çalıştırılabilir
RecordPatternsKalici.java
1import java.util.List;
2
3/**
4 * JAVA 21 - RECORD PATTERNS (JEP 440) - KALICI
5 * =============================================
6 *
7 * Bu dosya, record yikimini (destructuring) KALICI haliyle, ozellikle
8 * IC ICE (nested) yikim ve isimsiz desen (_) ile gosterir.
9 *
10 * EVRIM: Java 19 (1. preview) -> 20 (2. preview) -> 21 (KALICI)
11 *
12 * NOT: Isimsiz desen / degisken (_) Java 21'de hala PREVIEW'dir (JEP 443),
13 *      Java 22'de kalici oldu. Bu dosyada '_' kullanan KISIM ayri bir metotta
14 *      tutulmustur ve nasil derleneceği belirtilmistir. Diger her sey KALICIDIR.
15 *
16 * --- DERLEME / CALISTIRMA ---
17 *   KALICI kisimlar icin:
18 *     javac RecordPatternsKalici.java
19 *     java  RecordPatternsKalici
20 *
21 *   '_' (isimsiz desen) iceren satirlar Java 21'de PREVIEW gerektirir.
22 *   Bu dosyada o ozellik YORUM icinde gosterilmistir ki dosya --enable-preview
23 *   olmadan da derlensin. Denemek isterseniz yorumu acip soyle derleyin:
24 *     javac --release 21 --enable-preview RecordPatternsKalici.java
25 *     java  --enable-preview RecordPatternsKalici
26 */
27public class RecordPatternsKalici {
28
29    // Ic ice (nested) veri modeli
30    record Adres(String sehir, String ulke) {}
31    record Kullanici(String ad, Adres adres) {}
32    record Siparis(Kullanici musteri, double tutar) {}
33
34    public static void main(String[] args) {
35        System.out.println("=== JAVA 21: RECORD PATTERNS (KALICI) ===\n");
36
37        ornek1_basitYikim();
38        ornek2_icIceYikim();
39        ornek3_switchIleYikim();
40        ornek4_isimsizDesenNotu();
41    }
42
43    /** Basit yikim: bir record'un alanlarini dogrudan degiskenlere cikar. */
44    static void ornek1_basitYikim() {
45        System.out.println("--- Ornek 1: Basit yikim ---");
46        Object o = new Adres("Istanbul", "Turkiye");
47
48        // ESKI: o instanceof Adres a -> a.sehir(), a.ulke()
49        // YENI: dogrudan yikim
50        if (o instanceof Adres(String sehir, String ulke)) {
51            System.out.println("  Sehir: " + sehir + ", Ulke: " + ulke);
52        }
53        System.out.println();
54    }
55
56    /**
57     * IC ICE YIKIM: Record patterns'in en guclu yani.
58     * Siparis -> Kullanici -> Adres zincirini TEK desende cozer.
59     */
60    static void ornek2_icIceYikim() {
61        System.out.println("--- Ornek 2: Ic ice yikim (nested destructuring) ---");
62        Object o = new Siparis(
63                new Kullanici("Ayse", new Adres("Izmir", "Turkiye")),
64                1499.90);
65
66        // Tek satirda 4 seviye derinlige inip alanlari cikariyoruz
67        if (o instanceof Siparis(Kullanici(String ad, Adres(String sehir, String ulke)),
68                                 double tutar)) {
69            System.out.printf("  %s adli musteri (%s/%s) %.2f TL siparis verdi.%n",
70                    ad, sehir, ulke, tutar);
71        }
72        System.out.println();
73    }
74
75    /** switch + record pattern: tur ayrimi ve yikim bir arada. */
76    static void ornek3_switchIleYikim() {
77        System.out.println("--- Ornek 3: switch + record pattern ---");
78        List<Object> nesneler = List.of(
79                new Adres("Ankara", "Turkiye"),
80                new Kullanici("Mehmet", new Adres("Bursa", "Turkiye"))
81        );
82
83        for (Object o : nesneler) {
84            String mesaj = switch (o) {
85                case Adres(String s, String u) -> "Adres: " + s + " / " + u;
86                case Kullanici(String ad, Adres(String s, String u)) ->
87                        "Kullanici: " + ad + " (" + s + ")";
88                default -> "bilinmeyen";
89            };
90            System.out.println("  " + mesaj);
91        }
92        System.out.println();
93    }
94
95    /**
96     * ISIMSIZ DESEN (_) - Java 21'de PREVIEW (JEP 443), Java 22'de kalici.
97     * Kullanmadigimiz bilesenleri '_' ile gosterip niyeti netlestiririz.
98     *
99     * Asagidaki kod --enable-preview ile derlenir. Bu dosya varsayilan olarak
100     * preview'siz derlensin diye ornek YORUM icinde verilmistir:
101     *
102     *   if (o instanceof Siparis(Kullanici(String ad, _), double tutar)) {
103     *       // adres umurumuzda degil -> '_' ile atladik
104     *       System.out.println(ad + " -> " + tutar);
105     *   }
106     */
107    static void ornek4_isimsizDesenNotu() {
108        System.out.println("--- Ornek 4: Isimsiz desen (_) NOTU ---");
109        System.out.println("""
110                  Java 21'de '_' (isimsiz desen/degisken) PREVIEW'dir (JEP 443).
111                  Kullanilmayan bilesenleri '_' ile atlamayi saglar; ornegin:
112                      o instanceof Siparis(Kullanici(String ad, _), double tutar)
113                  Denemek icin: javac --release 21 --enable-preview ...
114                  Java 22'de bu ozellik KALICI olmustur.
115                """);
116    }
117}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

SequencedCollections

çalıştırılabilir
SequencedCollections.java
1import java.util.ArrayList;
2import java.util.LinkedHashMap;
3import java.util.LinkedHashSet;
4import java.util.List;
5import java.util.SequencedCollection;
6import java.util.SequencedMap;
7import java.util.SequencedSet;
8import java.util.TreeMap;
9
10/**
11 * JAVA 21 - SEQUENCED COLLECTIONS (JEP 431) - KALICI
12 * ===================================================
13 *
14 * Bu dosya, Java 21 ile gelen UC yeni arayuzu gosterir:
15 *   - SequencedCollection : getFirst/getLast/addFirst/addLast/removeFirst/removeLast/reversed
16 *   - SequencedSet        : SequencedCollection + Set
17 *   - SequencedMap        : firstEntry/lastEntry/putFirst/putLast/reversed/sequencedKeySet...
18 *
19 * NEDEN GELDI?
20 *   20+ yildir "ilk/son elemana ve ters siraya tutarli erisim" icin ortak bir
21 *   API yoktu. List'te get(0)/get(size-1), Deque'te getFirst/getLast, LinkedHashSet'te
22 *   ise son elemani almak cok zahmetliydi. Artik hepsinde AYNI API var.
23 *
24 * --- DERLEME / CALISTIRMA (KALICI; --enable-preview GEREKMEZ) ---
25 *   javac SequencedCollections.java
26 *   java  SequencedCollections
27 */
28public class SequencedCollections {
29
30    public static void main(String[] args) {
31        System.out.println("=== JAVA 21: SEQUENCED COLLECTIONS (KALICI) ===\n");
32
33        listeOrnegi();
34        setOrnegi();
35        mapOrnegi();
36        eskiVsYeni();
37    }
38
39    /** List zaten SequencedCollection'dir. */
40    static void listeOrnegi() {
41        System.out.println("--- SequencedCollection (List) ---");
42        SequencedCollection<String> liste = new ArrayList<>(List.of("A", "B", "C"));
43
44        System.out.println("  Ilk eleman  (getFirst): " + liste.getFirst());
45        System.out.println("  Son eleman  (getLast) : " + liste.getLast());
46
47        liste.addFirst("BAS");   // basa ekle
48        liste.addLast("SON");    // sona ekle
49        System.out.println("  Ekleme sonrasi        : " + liste);
50
51        System.out.println("  Ters cevrilmis (reversed): " + liste.reversed());
52
53        liste.removeFirst();
54        liste.removeLast();
55        System.out.println("  Bas/son silme sonrasi : " + liste + "\n");
56    }
57
58    /** LinkedHashSet artik SequencedSet'tir (eklenme sirasini korur). */
59    static void setOrnegi() {
60        System.out.println("--- SequencedSet (LinkedHashSet) ---");
61        SequencedSet<String> sonGoruntulenen = new LinkedHashSet<>();
62        sonGoruntulenen.add("Telefon");
63        sonGoruntulenen.add("Laptop");
64        sonGoruntulenen.add("Kulaklik");
65
66        // ESKIDEN LinkedHashSet'te son elemana erismek cok zordu!
67        System.out.println("  En ESKI goruntulenen (getFirst): " + sonGoruntulenen.getFirst());
68        System.out.println("  En YENI goruntulenen (getLast) : " + sonGoruntulenen.getLast());
69        System.out.println("  Ters sira (en yeni -> en eski) : " + sonGoruntulenen.reversed());
70        System.out.println();
71    }
72
73    /** LinkedHashMap ve TreeMap artik SequencedMap'tir. */
74    static void mapOrnegi() {
75        System.out.println("--- SequencedMap (LinkedHashMap) ---");
76        SequencedMap<String, Integer> sayfaZiyaretleri = new LinkedHashMap<>();
77        sayfaZiyaretleri.put("anasayfa", 1200);
78        sayfaZiyaretleri.put("urunler", 850);
79        sayfaZiyaretleri.put("iletisim", 300);
80
81        System.out.println("  Ilk giris (firstEntry): " + sayfaZiyaretleri.firstEntry());
82        System.out.println("  Son giris (lastEntry) : " + sayfaZiyaretleri.lastEntry());
83
84        sayfaZiyaretleri.putFirst("kampanya", 5000); // basa ekle
85        System.out.println("  putFirst sonrasi      : " + sayfaZiyaretleri);
86        System.out.println("  Ters sirali map       : " + sayfaZiyaretleri.reversed());
87
88        // TreeMap de SequencedMap'tir (sirali map)
89        SequencedMap<String, Integer> sirali = new TreeMap<>(sayfaZiyaretleri);
90        System.out.println("  TreeMap ilk anahtar   : " + sirali.firstEntry().getKey());
91        System.out.println();
92    }
93
94    static void eskiVsYeni() {
95        System.out.println("--- ESKI vs YENI ozet ---");
96        List<String> l = List.of("ilk", "orta", "son");
97        System.out.println("  ESKI son eleman: l.get(l.size()-1) = " + l.get(l.size() - 1));
98        System.out.println("  YENI son eleman: l.getLast()        = " + l.getLast());
99        System.out.println("""
100
101                  * Tum sirali koleksiyonlarda artik AYNI, tutarli API.
102                  * getFirst/getLast bos koleksiyonda NoSuchElementException firlatir.
103                  * reversed() bir GORUNUM (view) dondurur; ozgun koleksiyona baglidir.
104                """);
105    }
106}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

StringTemplatesPreview

ortam gerekir
StringTemplatesPreview.java
1/**
2 * JAVA 21 - STRING TEMPLATES (JEP 430) - 1. PREVIEW
3 * ==================================================
4 *
5 * Bu dosya, String Templates'in Java 21'deki preview halini gosterir.
6 *
7 * !!! COK ONEMLI UYARI !!!
8 *   String Templates Java 21 ve 22'de PREVIEW olarak kaldi; Java 23'te
9 *   tasarimdan KALDIRILDI (geri cekildi) ve yeniden tasarlanmak uzere
10 *   ertelendi. Bu yuzden URETIMDE KULLANMAYIN. Kavramsal olarak bilin.
11 *   Ileride farkli bir bicimde geri donmesi beklenir.
12 *
13 * NEDIR?
14 *   STR."... \{ifade} ..." sozdizimi ile guvenli, okunabilir string
15 *   interpolasyonu. Ayrica SQL/HTML gibi baglamlarda kacis (escaping) ve
16 *   dogrulama yapabilen sablon islemcileri (template processors) sunar.
17 *
18 * NEDEN GELDI?
19 *   - "+" ile birlestirme daginiktir.
20 *   - String.format argum sirasi hatalarina aciktir.
21 *   - Hicbiri enjeksiyon guvenligi (SQL injection / XSS) saglamaz.
22 *
23 * --- DERLEME / CALISTIRMA (PREVIEW oldugu icin GEREKLI) ---
24 *   javac --release 21 --enable-preview StringTemplatesPreview.java
25 *   java  --enable-preview StringTemplatesPreview
26 *
27 *   NOT: Java 23+ ile bu sozdizimi KALDIRILDIGI icin o surumlerde derlenmez.
28 *        Bu ornek Java 21/22 icindir.
29 */
30
31import static java.lang.StringTemplate.STR;
32
33public class StringTemplatesPreview {
34
35    public static void main(String[] args) {
36        System.out.println("=== JAVA 21: STRING TEMPLATES (1. PREVIEW) ===\n");
37
38        String isim = "Ayse";
39        int yas = 30;
40        double bakiye = 1499.90;
41
42        // --- ESKI yontemler ---
43        System.out.println("--- ESKI ---");
44        String eski1 = "Ad: " + isim + ", Yas: " + yas;
45        String eski2 = String.format("Ad: %s, Yas: %d", isim, yas);
46        System.out.println("  + ile      : " + eski1);
47        System.out.println("  format ile : " + eski2);
48        System.out.println();
49
50        // --- YENI: STR sablon islemcisi (preview) ---
51        System.out.println("--- YENI (STR, preview) ---");
52        String yeni = STR."Ad: \{isim}, Yas: \{yas}";
53        System.out.println("  STR ile    : " + yeni);
54
55        // Ifadeler de gomulebilir (sadece degisken degil)
56        String hesap = STR."\{isim} icin yillik bakiye: \{bakiye * 12} TL";
57        System.out.println("  Ifade ile  : " + hesap);
58
59        // Cok satirli sablon
60        String rapor = STR."""
61                === MUSTERI RAPORU ===
62                Ad     : \{isim}
63                Yas    : \{yas}
64                Bakiye : \{bakiye} TL
65                """;
66        System.out.println(rapor);
67
68        System.out.println("""
69                --- UYARI ---
70                Bu ozellik Java 23'te KALDIRILDI. Sadece Java 21/22'de --enable-preview
71                ile calisir. Uretimde kullanmayin; ileride yeniden tasarlanacaktir.
72                """);
73    }
74}
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.

StructuredConcurrency

ortam gerekir
StructuredConcurrency.java
1import java.time.Duration;
2import java.util.concurrent.StructuredTaskScope;
3
4/**
5 * JAVA 21 - STRUCTURED CONCURRENCY (JEP 453) - PREVIEW
6 * =====================================================
7 *
8 * Bu dosya, eszamanli alt gorevleri TEK BIR IS BIRIMI gibi yoneten
9 * StructuredTaskScope'u gosterir. Virtual Threads ile mukemmel calisir.
10 *
11 * NEDIR?
12 *   Bir gorevin alt gorevleri birlikte baslar, birlikte tamamlanir veya
13 *   birlikte iptal olur. Hata yayilimi ve iptal OTOMATIKTIR.
14 *
15 * NEDEN GELDI?
16 *   Manuel ExecutorService + Future kullaniminda:
17 *     - bir alt gorev patlarsa digerlerini iptal etmek zor,
18 *     - sizinti (leak) onlemek zor,
19 *     - kontrol akisi dagilir ("unstructured concurrency").
20 *   StructuredTaskScope bu sorunlari yapisal olarak cozer. Her alt gorev bir
21 *   VIRTUAL THREAD'de calisir (cok ucuz), bu yuzden Loom'un dogal tamamlayicisidir.
22 *
23 * --- DERLEME / CALISTIRMA (Java 21'de PREVIEW oldugu icin GEREKLI) ---
24 *   javac --release 21 --enable-preview StructuredConcurrency.java
25 *   java  --enable-preview StructuredConcurrency
26 *
27 *   NOT: StructuredTaskScope API'si surumler arasinda degisebilir (preview).
28 */
29public class StructuredConcurrency {
30
31    public static void main(String[] args) throws Exception {
32        System.out.println("=== JAVA 21: STRUCTURED CONCURRENCY (PREVIEW) ===\n");
33
34        basariliSenaryo();
35        System.out.println();
36        hataliSenaryo();
37    }
38
39    /**
40     * GERCEK HAYAT: Bir kullanici profil sayfasi icin 3 farkli servisten
41     * paralel veri cekiyoruz. ShutdownOnFailure: biri patlarsa digerleri iptal.
42     */
43    static void basariliSenaryo() throws Exception {
44        System.out.println("--- Basarili senaryo (3 servis paralel) ---");
45        long t0 = System.currentTimeMillis();
46
47        // try-with-resources: scope kapaninca tum alt gorevler temizlenir
48        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
49            // Her fork() bir VIRTUAL thread'de calisir
50            var kullaniciF  = scope.fork(() -> servisCagir("Kullanici servisi", 150, "Ayse"));
51            var siparisF    = scope.fork(() -> servisCagir("Siparis servisi", 200, "42 siparis"));
52            var oneriF      = scope.fork(() -> servisCagir("Oneri servisi", 100, "5 oneri"));
53
54            scope.join();              // hepsinin bitmesini bekle
55            scope.throwIfFailed();     // biri patladiysa istisna firlat
56
57            // Hepsi basarili -> sonuclari birlestir
58            System.out.println("  SONUC: " + kullaniciF.get()
59                    + " | " + siparisF.get() + " | " + oneriF.get());
60        }
61
62        long sure = System.currentTimeMillis() - t0;
63        System.out.println("  Toplam sure: " + sure + " ms");
64        System.out.println("  (Seri olsa ~450 ms surerdi; paralel oldugu icin ~en yavas "
65                + "gorev kadar = ~200 ms.)");
66    }
67
68    /**
69     * Bir alt gorev hata firlatirsa: ShutdownOnFailure DIGER alt gorevleri
70     * OTOMATIK iptal eder ve hatayi yukari yayar. Sizinti olmaz.
71     */
72    static void hataliSenaryo() throws InterruptedException {
73        System.out.println("--- Hatali senaryo (bir servis patliyor) ---");
74        try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
75            scope.fork(() -> servisCagir("Hizli servis", 50, "OK"));
76            scope.fork(() -> {
77                Thread.sleep(Duration.ofMillis(80));
78                throw new RuntimeException("Odeme servisi cevap vermedi!");
79            });
80
81            scope.join();
82            scope.throwIfFailed(); // RuntimeException buradan firlar
83            System.out.println("  Buraya ulasilmaz.");
84        } catch (Exception e) {
85            // Diger alt gorevler otomatik iptal edildi
86            System.out.println("  YAKALANAN HATA: " + e.getCause().getMessage());
87            System.out.println("  (Diger alt gorevler otomatik iptal edildi; sizinti yok.)");
88        }
89    }
90
91    /** Bloklayici bir servis cagrisini taklit eder. */
92    static String servisCagir(String ad, int ms, String sonuc) throws InterruptedException {
93        Thread.sleep(Duration.ofMillis(ms));
94        System.out.println("    [" + ad + "] tamamlandi (" + ms + " ms)");
95        return sonuc;
96    }
97}
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.

UnnamedMainMethod

çalıştırılabilir
UnnamedMainMethod.java
1/**
2 * JAVA 21 - UNNAMED CLASSES & INSTANCE MAIN METHODS (JEP 445) - PREVIEW
3 * =====================================================================
4 *
5 * Bu dosya, yeni baslayanlar icin BASITLESTIRILMIS main yazimini anlatir.
6 *
7 * NEDIR?
8 *   Java'da en basit programi bile yazmak icin tum seremoniyi (sinif bildirimi,
9 *   public, static, void, String[] args) ogrenmek gerekiyordu. JEP 445 bunu
10 *   gevsetir:
11 *     - INSTANCE main: 'static' olmayan, parametresiz 'void main()' yazilabilir.
12 *     - UNNAMED CLASS: bir dosyada sinif govdesi yazmadan dogrudan metot/alan
13 *       tanimlanabilir; derleyici gorunmez bir sinif olusturur.
14 *
15 * NEDEN GELDI?
16 *   Egitimde ilk engeli kaldirmak. Ogrenci "Merhaba Dunya" icin OOP, static,
17 *   dizi gibi kavramlari bilmeden basit kod yazabilsin.
18 *
19 * !!! ONEMLI: BU DOSYA NORMAL (ISIMLI) BIR SINIFTIR !!!
20 *   Gercek "unnamed class" ozelligi, sinif bildirimi OLMAYAN bir kaynak dosya
21 *   gerektirir (asagida aciklandi). Bu dosya derlenebilir kalsin diye normal
22 *   sinif olarak yazilmistir; preview sozdizimi YORUM icinde gosterilmistir.
23 *
24 * --- DERLEME / CALISTIRMA (bu normal dosya icin; preview gerekmez) ---
25 *   javac UnnamedMainMethod.java
26 *   java  UnnamedMainMethod
27 *
28 * --- GERCEK UNNAMED CLASS'I DENEMEK ICIN (preview) ---
29 *   Asagidaki ornegi 'Merhaba.java' adli AYRI bir dosyaya, sinif bildirimi
30 *   OLMADAN yazin:
31 *
32 *       void main() {
33 *           System.out.println("Merhaba Dunya");
34 *       }
35 *
36 *   Sonra Java 21'de soyle calistirin:
37 *       java --release 21 --enable-preview --source 21 Merhaba.java
38 *   veya tek dosya kaynak modunda:
39 *       java --enable-preview --source 21 Merhaba.java
40 *
41 *   EVRIM: Java 21 (preview) -> 22, 23 (gelisen preview) -> Java 25 (KALICI,
42 *          "Compact Source Files and Instance Main Methods" olarak).
43 */
44public class UnnamedMainMethod {
45
46    public static void main(String[] args) {
47        System.out.println("=== JAVA 21: UNNAMED CLASSES & INSTANCE MAIN (PREVIEW) ===\n");
48
49        System.out.println("--- ESKI (tam seremoni) ---");
50        System.out.println("""
51                  public class Merhaba {
52                      public static void main(String[] args) {
53                          System.out.println("Merhaba Dunya");
54                      }
55                  }
56                """);
57
58        System.out.println("--- YENI (preview, ayri 'Merhaba.java' dosyasinda) ---");
59        System.out.println("""
60                  void main() {
61                      System.out.println("Merhaba Dunya");
62                  }
63                """);
64
65        System.out.println("--- ARA ADIM: instance main (sinif var, static yok) ---");
66        System.out.println("""
67                  public class Merhaba {
68                      void main() {                 // 'static' ve 'String[] args' YOK
69                          System.out.println("Merhaba Dunya");
70                      }
71                  }
72                """);
73
74        System.out.println("""
75                --- AVANTAJ / RISK ---
76                * Avantaj : Yeni baslayan dostu; ogrenme egrisini yumusatir.
77                * Risk    : Java 21'de PREVIEW; sozdizimi surumler arasi degisti.
78                            Kalici hali Java 25'tedir. Egitim/deneme disinda kullanmayin.
79                """);
80    }
81}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

VirtualThreadsKalici

çalıştırılabilir
VirtualThreadsKalici.java
1import java.time.Duration;
2import java.time.Instant;
3import java.util.ArrayList;
4import java.util.List;
5import java.util.concurrent.ExecutorService;
6import java.util.concurrent.Executors;
7import java.util.concurrent.Future;
8import java.util.concurrent.atomic.AtomicLong;
9
10/**
11 * JAVA 21 - VIRTUAL THREADS (JEP 444) - KALICI - Project Loom
12 * ===========================================================
13 *
14 * Bu dosya, Java 21'in BAYRAK ozelligi olan Virtual Threads'i derinlemesine
15 * gosterir. Klasik (platform) thread havuzu ile virtual thread modelini,
16 * COK SAYIDA esZAMANLI BLOKLAYICI ISTEK senaryosunda kiyaslar.
17 *
18 * ==================== KAVRAMSAL OZET ====================
19 * PLATFORM THREAD:
20 *   - OS thread'inin 1:1 sarmalayicisi. ~1 MB stack. OS kaynagi.
21 *   - Sayisi sinirli (~binlerce). Bloklaninca pahali OS thread bosta bekler.
22 * VIRTUAL THREAD:
23 *   - JVM yonetimli, cok hafif. Milyonlarca olabilir.
24 *   - Az sayida "carrier" OS thread uzerinde coklanir.
25 *   - Bloklayici I/O'da carrier'dan SOKULUR (unmount); carrier baska virtual
26 *     thread'e gecer. Boylece OS thread asla bosta beklemez (MOUNT/UNMOUNT).
27 *
28 * NEDEN DEVRIM:
29 *   "thread-per-request" modelinde basit/senkron kod yazarsiniz ama platform
30 *   thread'lerle olceklenmez. Reaktif programlama olceklenir ama kod karmasik
31 *   olur. Virtual threads = BASIT KOD + DEVASA OLCEKLENME.
32 *
33 * ==================== DERLEME / CALISTIRMA ====================
34 * Virtual Threads Java 21'de KALICIDIR; --enable-preview GEREKMEZ.
35 *   javac VirtualThreadsKalici.java
36 *   java  VirtualThreadsKalici
37 *
38 * Tasiyici (carrier) thread sayisini gozlemlemek isterseniz:
39 *   java -Djdk.virtualThreadScheduler.parallelism=4 VirtualThreadsKalici
40 */
41public class VirtualThreadsKalici {
42
43    /** Her "istek" ~200 ms bloklayici I/O (DB/HTTP cagrisi) taklit eder. */
44    static final Duration ISTEK_GECIKMESI = Duration.ofMillis(200);
45
46    public static void main(String[] args) throws Exception {
47        System.out.println("=== JAVA 21: VIRTUAL THREADS (KALICI) ===\n");
48        System.out.println("Mevcut islemci sayisi: "
49                + Runtime.getRuntime().availableProcessors() + "\n");
50
51        // Senaryo: 10.000 eszamanli "istek". Her biri 200 ms bloklayici bekleme.
52        // Ideal sure ~200 ms olmali (hepsi paralel beklerse).
53        int istekSayisi = 10_000;
54
55        System.out.println("--- KIYAS: " + istekSayisi
56                + " eszamanli bloklayici istek ---\n");
57
58        // 1) KLASIK: sabit boyutlu PLATFORM thread havuzu (200 thread)
59        //    -> ayni anda en fazla 200 istek; geri kalanlar KUYRUKTA bekler.
60        //    -> bu yuzden toplam sure cok daha uzun olur.
61        platformHavuzuIleCalistir(istekSayisi, 200);
62
63        // 2) MODERN: her gorev icin bir VIRTUAL thread
64        //    -> 10.000 istek AYNI ANDA bloklanir; OS thread'leri bu sirada
65        //       baska isteklere hizmet eder. Toplam sure ~tek istek suresine yakin.
66        virtualThreadIleCalistir(istekSayisi);
67
68        // 3) Virtual thread'in ic yapisini gosteren mini ornek
69        icYapiOrnegi();
70
71        // 4) Onemli uyarilar
72        uyarilar();
73    }
74
75    /**
76     * KLASIK MODEL: Sabit havuz. 200 platform thread, 10.000 gorev.
77     * Gorevler 200'erli partiler halinde isler -> ~ (10000/200) * 200ms = ~10 sn.
78     */
79    static void platformHavuzuIleCalistir(int istekSayisi, int havuzBoyutu)
80            throws InterruptedException {
81        System.out.println(">> 1) KLASIK PLATFORM THREAD HAVUZU (boyut=" + havuzBoyutu + ")");
82        AtomicLong tamamlanan = new AtomicLong();
83
84        Instant baslangic = Instant.now();
85        try (ExecutorService es = Executors.newFixedThreadPool(havuzBoyutu)) {
86            for (int i = 0; i < istekSayisi; i++) {
87                es.submit(() -> {
88                    bloklayiciIstekTaklit();          // ~200 ms bekle
89                    tamamlanan.incrementAndGet();
90                });
91            }
92        } // close() -> tum gorevler bitene kadar bekler
93        Duration sure = Duration.between(baslangic, Instant.now());
94
95        System.out.println("   Tamamlanan istek : " + tamamlanan.get());
96        System.out.println("   Toplam sure      : " + sure.toMillis() + " ms");
97        System.out.println("   (Sadece 200 thread oldugu icin istekler partiler "
98                + "halinde islendi; sure uzadi.)\n");
99    }
100
101    /**
102     * MODERN MODEL: Her gorev icin bir virtual thread.
103     * 10.000 istek ayni anda bloklanir; toplam sure ~200 ms'ye yakin olur.
104     */
105    static void virtualThreadIleCalistir(int istekSayisi) throws InterruptedException {
106        System.out.println(">> 2) VIRTUAL THREAD (her gorev icin bir tane)");
107        AtomicLong tamamlanan = new AtomicLong();
108
109        Instant baslangic = Instant.now();
110        // newVirtualThreadPerTaskExecutor: her submit yeni bir virtual thread acar
111        try (ExecutorService es = Executors.newVirtualThreadPerTaskExecutor()) {
112            for (int i = 0; i < istekSayisi; i++) {
113                es.submit(() -> {
114                    bloklayiciIstekTaklit();          // ~200 ms bekle (carrier'dan sokulur)
115                    tamamlanan.incrementAndGet();
116                });
117            }
118        }
119        Duration sure = Duration.between(baslangic, Instant.now());
120
121        System.out.println("   Tamamlanan istek : " + tamamlanan.get());
122        System.out.println("   Toplam sure      : " + sure.toMillis() + " ms");
123        System.out.println("   (10.000 istek AYNI ANDA bekledi; az sayida OS thread "
124                + "bu beklemeleri coklayarak yonetti.)\n");
125    }
126
127    /** Bloklayici bir ag/DB cagrisini taklit eder (CPU degil, BEKLEME aginlikli). */
128    static void bloklayiciIstekTaklit() {
129        try {
130            Thread.sleep(ISTEK_GECIKMESI);
131        } catch (InterruptedException e) {
132            Thread.currentThread().interrupt();
133        }
134    }
135
136    /** Virtual thread'in kimligini ve carrier davranisini gosteren mini ornek. */
137    static void icYapiOrnegi() throws Exception {
138        System.out.println(">> 3) VIRTUAL THREAD IC YAPISI");
139
140        List<Future<String>> sonuclar = new ArrayList<>();
141        try (var es = Executors.newVirtualThreadPerTaskExecutor()) {
142            for (int i = 1; i <= 3; i++) {
143                int no = i;
144                sonuclar.add(es.submit(() -> {
145                    Thread t = Thread.currentThread();
146                    // isVirtual() -> true; thread adi tipik olarak bossa "VirtualThread[#...]"
147                    return "  Gorev " + no + " | virtual mi? " + t.isVirtual()
148                            + " | " + t;
149                }));
150            }
151        }
152        for (Future<String> f : sonuclar) System.out.println(f.get());
153        System.out.println();
154    }
155
156    static void uyarilar() {
157        System.out.println(">> 4) ONEMLI UYARILAR");
158        System.out.println("""
159                * Virtual thread'leri HAVUZLAMAYIN. Onlar ucuzdur; her gorev icin
160                  YENISINI acin (newVirtualThreadPerTaskExecutor). Havuzlamak anti-pattern'dir.
161                * CPU-yogun (hesaplama agirlikli) islerde fayda saglamaz; onlar thread'i
162                  zaten mesgul tutar. Virtual thread'in kazanci I/O BEKLEMESINDEDIR.
163                * 'synchronized' icinde bloklanmak PINNING'e yol acabilir (virtual thread
164                  carrier'dan sokulemez). Cozum: ReentrantLock kullanin.
165                * Java 21'de KALICIDIR: --enable-preview gerekmez. Spring Boot 3.2+, Tomcat,
166                  Helidon, Quarkus tek bir bayrakla virtual thread'i etkinlestirir.
167                """);
168    }
169}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.