Eğitim Portalı/Java/Java Sürüm Evrimi (8 → 25)
Java01-java/20-surum-evrimi-java8-25

Java Sürüm Evrimi (8 → 25)

Java, 2014'teki 8 sürümünden bu yana her 6 ayda bir yeni sürüm, her 2 yılda bir uzun destekli (LTS) sürüm çıkarıyor. LTS'ler: 8, 11, 17, 21, 25. Bu bölümün amacı sadece "şu özellik hangi sürümde geldi" demek değil; he…

Java Sürüm Evrimi (8 → 25)

Java, 2014'teki 8 sürümünden bu yana her 6 ayda bir yeni sürüm, her 2 yılda bir uzun destekli (LTS) sürüm çıkarıyor. LTS'ler: 8, 11, 17, 21, 25. Bu bölümün amacı sadece "şu özellik hangi sürümde geldi" demek değil; her sürümde neyin önemli olduğunu ve bir sürümden diğerine geçerken kodun nasıl değiştiğini karşılaştırmalı, çalışan örneklerle göstermek. Örnekler bu ortamdaki JDK 21 ile uyumludur; her örnek "öncesi vs sonrası" stiliyle yazılmıştır (iki stil de 21'de derlenir, böylece farkı doğrudan görürsün).

Java 8 (2014, LTS) — Dili yeniden tanımlayan devrim

En önemli sürüm. Java'yı modern, fonksiyonel-etkili bir dile dönüştürdü:

ÖzellikNe işe yararNeyi değiştirdi
LambdaDavranışı değer gibi taşımaAnonim iç sınıf gürültüsü bitti
Stream APIBildirimsel veri işlemefor döngüleri yerini filter/map/collect'e bıraktı
Optionalnull güvenliği"milyar dolarlık hata"ya tip düzeyinde önlem
java.timeTarih/saatHatalı, değişebilen Date/Calendar'ın halefi
default metotlarInterface'e gövdeli metotAPI'leri bozmadan genişletme

Örnek 1 (./Ornek1.java) dört işi Java 8 öncesi ve sonrası yan yana yapar: anonim Comparator→lambda, döngü→stream, elle null kontrolü→Optional, Datejava.time. Aynı sonuç, çok daha temiz kod.

Geçiş notu: 8'e geçişin pratikte dezavantajı yoktu; bugün hâlâ 8'de kalan projeler güvenlik ve performans güncellemelerini kaçırır.

Java 9–11 — Modülerlik, var ve araçlar

  • Java 9 (2017): Modül sistemi (JPMS/Jigsaw), List/Map.of fabrikaları, jshell, Stream eklentileri (takeWhile, dropWhile, 3-argümanlı iterate).
  • Java 10 (2018): var — yerel değişken tip çıkarımı.
  • Java 11 (2018, LTS): Yeni String metotları (strip, isBlank, repeat, lines), standart HttpClient, tek dosya çalıştırma (java Dosya.java — bu portalın temeli!).

Örnek 2 (./Ornek2.java) koleksiyon fabrikalarını (3 adım vs List.of), var'ı, Java 11 String metotlarını ve Java 9 Stream eklentilerini öncesi/sonrası karşılaştırır.

Geçiş notu (8→11): En büyük tuzak, 11'de kaldırılan Java EE/CORBA modülleridir (JAXB, JAX-WS). Bunları kullanan projeler bağımlılıkları ayrıca eklemek zorunda kaldı.

Java 14–17 — Dil ergonomisi olgunlaşıyor

Bu aralık, kodu belirgin biçimde kısaltan özellikler getirdi:

Özellik (sürüm)ÖncesiSonrası
switch expression (14)break'li statement, mutable değişkenDeğer döndüren, eksiksizlik denetimli ifade
text block (15)"\n" + + cehennemi"""...""" çok satırlı metin
records (16)~30 satır boilerplate veri sınıfıTek satır (record)
pattern matching instanceof (16)instanceof + ayrı castTek adımda kontrol + bağlama
sealed sınıflar (17, LTS)Kontrolsüz kalıtımKapalı, denetlenebilir hiyerarşi

Örnek 3 (./Ornek3.java) bir record'u elle yazılmış sınıfla, switch expression'ı statement'la, pattern matching'i instanceof+cast ile ve sealed+switch'i karşılaştırır.

Java 18–21 — Eşzamanlılıkta sıçrama

  • Java 18 (2022): UTF-8 varsayılan karakter kümesi, basit web sunucusu (jwebserver).
  • Java 21 (2023, LTS): Önceki sürümlerde önizleme olan büyük özellikler standartlaştı:
    • Virtual threads — on binlerce eşzamanlı görevi ucuza
    • Record patterns + switch pattern matching — veriyi switch'te parçalama
    • Sequenced CollectionsgetFirst/getLast/reversed
    • Generational ZGC — düşük gecikmeli çöp toplama

Örnek 4 (./Ornek4.java) record patterns'ı iç içe instanceof ile, sequenced collections'ı get(0)/get(size-1) ile ve sanal thread'leri platform thread havuzuyla karşılaştırır (G/Ç ağırlıklı yükte sanal thread'lerin farkını ölçer).

Geçiş notu (17→21): Genelde düşük riskli, yüksek kazançlı bir geçiştir. Sanal thread kullanacaksan synchronized bloklarındaki "pinning"e dikkat (kritik bölümlerde ReentrantLock).

Java 22–25 — En yeni (JDK 25 gerektirir, burada çalışmaz)

Yalnızca tanıtım amaçlı (bu ortamdaki JDK 21'de derlenmez):

  • Java 22 (2024): Foreign Function & Memory API (JNI halefi) standartlaştı; isimsiz değişkenler/desenler (_).
  • Java 24 (2025): Stream Gatherers (Stream.gather(...)) ile özel ara işlemler.
  • Java 25 (2025, LTS): Sadeleştirilmiş giriş noktası (void main()), modül import bildirimleri (import module java.base;), scoped values, esnek constructor gövdeleri.
// Java 25: sade kaynak dosya + instance main (örnek; JDK 25 gerektirir)
void main() {
    IO.println("Merhaba"); // "public static void main(String[])" şart değil
}

Not: 22–25'teki bazı özelliklerin "önizleme → standart" yolculuğu sürümden sürüme değişebilir; kesin durum için resmî sürüm notlarına bak.

Sürüm-sürüm derin anlatım (ayrı konular)

Bu konu genel resmi ve dönemsel karşılaştırmaları verir. Her sürümün ayrı, derin anlatımı ve "öncesi vs sonrası" örnekleri için şu konulara bak:

  • Java 8 → 16: 54-java862-java16 (her biri çalışan karşılaştırmalı örneklerle)
  • Java 17 → 21: 97-java17101-java21 (LTS'ler dahil; örnekler bu ortamda çalışır)
  • Java 22 → 25: 102-java22105-java25 (en yeni; JDK 21'de çalışmadığından kavramsal anlatım)

Yani her sürüm için "o sürümde ne önemli + bir önceki sürümden ne değişti" sorusu, ilgili konuda örneklerle yanıtlanır.

Sürüm seçerken pratik kural

  • Üretim için her zaman bir LTS (17, 21 veya 25). Ara sürümler kısa desteklidir.
  • Yeni projede bugün 21 (veya destekleniyorsa 25) mantıklı varsayılandır.
  • Çoğu zaman seçimini kütüphane/çerçeve uyumu belirler (kullandığın Spring/Hibernate hangi JDK'yı destekliyor?).

Özet

Java'nın 8'deki lambda/Stream devriminden 11'in modülerlik/araçlarına, 17'nin record/sealed ergonomisine ve 21'in sanal thread'lerine uzanan evrimini öncesi/sonrası karşılaştırmalı örneklerle gördük; 22–25'in en yeni eklerine değindik. Her geçişin kazanımları genelde maliyetinden büyüktür — ama riskler de vardır. Sırada tam olarak bunu konuşuyoruz: sürüm geçişi: riskler ve kazanımlar (özellikle 17/21 → en yeni).

Kod Örnekleri(4)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: JAVA 8 DEVRİMİ — "öncesi vs sonrası" karşılaştırması.
2// Aynı işleri Java 8 öncesi stil ve Java 8 stiliyle yan yana yazıp farkı görüyoruz.
3// (İki stil de JDK 21'de çalışır; amaç değişimi göstermektir.)
4// Çalıştırma: java Ornek1.java
5import java.text.SimpleDateFormat;
6import java.util.ArrayList;
7import java.util.Comparator;
8import java.util.Date;
9import java.util.List;
10import java.util.Optional;
11import java.time.LocalDate;
12import java.time.format.DateTimeFormatter;
13import java.util.stream.Collectors;
14
15public class Ornek1 {
16
17    record Urun(String ad, double fiyat) {}
18
19    public static void main(String[] args) {
20        List<Urun> urunler = List.of(
21                new Urun("Klavye", 450), new Urun("Mouse", 250),
22                new Urun("Monitör", 3200), new Urun("Kulaklık", 900));
23
24        // ============ 1) Sıralama: anonim sınıf (eski) vs lambda (Java 8) ============
25        List<Urun> eskiSirali = new ArrayList<>(urunler);
26        eskiSirali.sort(new Comparator<Urun>() {           // ESKİ: anonim iç sınıf, 5 satır gürültü
27            @Override public int compare(Urun a, Urun b) {
28                return Double.compare(a.fiyat(), b.fiyat());
29            }
30        });
31        List<Urun> yeniSirali = new ArrayList<>(urunler);
32        yeniSirali.sort(Comparator.comparingDouble(Urun::fiyat)); // JAVA 8: tek satır lambda/method ref
33
34        System.out.println("Sıralama sonucu aynı mı? "
35                + eskiSirali.equals(yeniSirali) + "  (anonim sınıf vs lambda)");
36
37        // ============ 2) Filtreleme+toplama: döngü (eski) vs Stream (Java 8) ============
38        // ESKİ: elle döngü, geçici liste
39        double eskiToplam = 0;
40        for (Urun u : urunler) {
41            if (u.fiyat() >= 500) eskiToplam += u.fiyat();
42        }
43        // JAVA 8: bildirimsel stream pipeline
44        double yeniToplam = urunler.stream()
45                .filter(u -> u.fiyat() >= 500)
46                .mapToDouble(Urun::fiyat)
47                .sum();
48        System.out.println("500+ ürün cirosu (döngü vs stream): " + eskiToplam + " == " + yeniToplam);
49
50        // İsim listesi: döngü vs stream+collect
51        List<String> adlar = urunler.stream().map(Urun::ad).collect(Collectors.toList());
52        System.out.println("Adlar (stream): " + adlar);
53
54        // ============ 3) null kontrolü: elle (eski) vs Optional (Java 8) ============
55        Urun bulunan = bul(urunler, "Mouse");
56        String eskiAd = (bulunan != null) ? bulunan.ad() : "yok";              // ESKİ: elle null kontrol
57        String yeniAd = Optional.ofNullable(bul(urunler, "Yok")).map(Urun::ad).orElse("yok"); // JAVA 8
58        System.out.println("null güvenliği: eski=" + eskiAd + ", optional=" + yeniAd);
59
60        // ============ 4) Tarih: Date/SimpleDateFormat (eski) vs java.time (Java 8) ============
61        // ESKİ: Date + SimpleDateFormat (değişebilir, thread-safe değil)
62        String eskiTarih = new SimpleDateFormat("dd.MM.yyyy").format(new Date(0L));
63        // JAVA 8: java.time (değişmez, güvenli, okunaklı)
64        String yeniTarih = LocalDate.of(1970, 1, 1).format(DateTimeFormatter.ofPattern("dd.MM.yyyy"));
65        System.out.println("tarih (Date vs java.time): " + eskiTarih + " == " + yeniTarih);
66
67        System.out.println("""
68
69                --- Java 8 NE getirdi? (en kritik sürüm) ---
70                Lambda + Stream + Optional + java.time + interface default metotları.
71                Etki: anonim sınıf gürültüsü gitti, döngüler bildirimsel oldu, null ve tarih güvenli hale geldi.
72                Bugün yazdığın modern Java'nın temeli bu sürümle atıldı.""");
73    }
74
75    static Urun bul(List<Urun> liste, String ad) {
76        return liste.stream().filter(u -> u.ad().equals(ad)).findFirst().orElse(null);
77    }
78}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: JAVA 9-11 — koleksiyon fabrikaları, var, yeni String metotları, Stream eklentileri.
2// "Öncesi vs sonrası" karşılaştırmalarıyla 9, 10 ve 11'in getirdikleri.
3// Çalıştırma: java Ornek2.java
4import java.util.ArrayList;
5import java.util.Collections;
6import java.util.List;
7import java.util.stream.Collectors;
8import java.util.stream.Stream;
9
10public class Ornek2 {
11
12    public static void main(String[] args) {
13        // ============ JAVA 9: değişmez koleksiyon fabrikaları ============
14        // ESKİ: liste oluştur, doldur, unmodifiable'a sar (3 adım)
15        List<String> eski = new ArrayList<>();
16        eski.add("a"); eski.add("b"); eski.add("c");
17        List<String> eskiDegismez = Collections.unmodifiableList(eski);
18        // JAVA 9: tek satır
19        List<String> yeni = List.of("a", "b", "c");
20        System.out.println("Koleksiyon fabrikası (eski vs List.of): " + eskiDegismez.equals(yeni));
21
22        // ============ JAVA 10: var ile yerel değişken tip çıkarımı ============
23        // ESKİ: tip iki kez yazılır
24        List<String> acikTip = new ArrayList<>();
25        // JAVA 10: tip çıkarılır (sağ taraftan)
26        var cikarilanTip = new ArrayList<String>();
27        acikTip.add("x"); cikarilanTip.add("x");
28        System.out.println("var (açık tip vs var): " + acikTip.equals(cikarilanTip));
29
30        // ============ JAVA 11: yeni String metotları ============
31        String metin = "  merhaba  ";
32        System.out.println("\n--- Java 11 String metotları ---");
33        System.out.println("strip()  : '" + metin.strip() + "'  (trim'den Unicode-doğru hali)");
34        System.out.println("isBlank(): " + "   ".isBlank());
35        System.out.println("repeat(3): " + "ab".repeat(3));
36        System.out.println("lines()  : " + "a\nb\nc".lines().count() + " satır");
37
38        // ============ JAVA 9: Stream eklentileri (takeWhile / dropWhile / iterate) ============
39        System.out.println("\n--- Java 9 Stream eklentileri ---");
40        List<Integer> sayilar = List.of(1, 2, 3, 4, 5, 1, 2);
41        // takeWhile: koşul bozulana kadar al
42        System.out.println("takeWhile(<4): " + sayilar.stream().takeWhile(n -> n < 4).collect(Collectors.toList()));
43        // dropWhile: koşul bozulana kadar atla
44        System.out.println("dropWhile(<4): " + sayilar.stream().dropWhile(n -> n < 4).collect(Collectors.toList()));
45        // iterate (3 argümanlı, Java 9): klasik for gibi
46        System.out.println("iterate      : " + Stream.iterate(1, n -> n <= 16, n -> n * 2).collect(Collectors.toList()));
47
48        System.out.println("""
49
50                --- Java 9-11 NE getirdi? ---
51                Java 9 : Modül sistemi (JPMS), List/Map.of, jshell, Stream eklentileri.
52                Java 10: var (yerel tip çıkarımı).
53                Java 11 (LTS): yeni String metotları, standart HttpClient, TEK DOSYA çalıştırma (java Dosya.java).
54                Geçiş tuzağı: Java 11'de Java EE/CORBA modülleri KALDIRILDI (JAXB/JAX-WS ayrı eklenir).""");
55    }
56}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek3

çalıştırılabilir
Ornek3.java
1// Ornek3: JAVA 14-17 — records, switch expression, pattern matching, sealed (öncesi vs sonrası).
2// Çalıştırma: java Ornek3.java
3import java.util.Objects;
4
5public class Ornek3 {
6
7    // ============ record (Java 16): "öncesi" tam bir sınıf, "sonrası" tek satır ============
8    // ÖNCESİ: değişmez bir veri sınıfı için onlarca satır boilerplate gerekirdi.
9    static final class NoktaEski {
10        private final int x, y;
11        NoktaEski(int x, int y) { this.x = x; this.y = y; }
12        int x() { return x; } int y() { return y; }
13        @Override public boolean equals(Object o) {
14            if (!(o instanceof NoktaEski n)) return false;
15            return x == n.x && y == n.y;
16        }
17        @Override public int hashCode() { return Objects.hash(x, y); }
18        @Override public String toString() { return "NoktaEski[x=" + x + ", y=" + y + "]"; }
19    }
20    // SONRASI (Java 16): tek satır — equals/hashCode/toString/getter'lar OTOMATİK.
21    record Nokta(int x, int y) {}
22
23    sealed interface Sekil permits Daire, Kare {}        // Java 17: kapalı hiyerarşi
24    record Daire(double r) implements Sekil {}
25    record Kare(double k) implements Sekil {}
26
27    public static void main(String[] args) {
28        System.out.println("record (eski sınıf vs record): "
29                + new NoktaEski(1, 2).equals(new NoktaEski(1, 2)) + " / " + new Nokta(1, 2).equals(new Nokta(1, 2)));
30        System.out.println("record toString: " + new Nokta(3, 4));
31
32        // ============ switch: statement (eski) vs expression (Java 14) ============
33        int gun = 6;
34        // ESKİ: switch statement — break, mutable değişken, hataya açık
35        String tipEski;
36        switch (gun) {
37            case 6: case 7: tipEski = "hafta sonu"; break;
38            default: tipEski = "hafta içi";
39        }
40        // YENİ (Java 14): switch expression — değer döndürür, break yok, eksiksizlik denetimi
41        String tipYeni = switch (gun) {
42            case 6, 7 -> "hafta sonu";
43            default -> "hafta içi";
44        };
45        System.out.println("\nswitch (statement vs expression): " + tipEski + " == " + tipYeni);
46
47        // ============ pattern matching for instanceof (Java 16) ============
48        Object o = "merhaba";
49        // ESKİ: instanceof + ayrı cast
50        if (o instanceof String) {
51            String s = (String) o;
52            System.out.println("\neski instanceof+cast: uzunluk " + s.length());
53        }
54        // YENİ: tek adımda kontrol + bağlama
55        if (o instanceof String s) {
56            System.out.println("yeni pattern matching: uzunluk " + s.length());
57        }
58
59        // ============ sealed + switch pattern (Java 17) ============
60        Sekil sekil = new Daire(2);
61        // sealed olduğu için switch EKSİKSİZ (default gerekmez); derleyici tüm tipleri zorlar.
62        double alan = switch (sekil) {
63            case Daire d -> Math.PI * d.r() * d.r();
64            case Kare k -> k.k() * k.k();
65        };
66        System.out.printf("%nsealed + switch: alan = %.2f%n", alan);
67
68        System.out.println("""
69
70                --- Java 14-17 NE getirdi? ---
71                switch expression (14), text block (15), records (16), pattern matching instanceof (16),
72                sealed sınıflar (17, LTS). Etki: çok daha az boilerplate, daha güvenli ve okunaklı modelleme.
73                Java 17 bugün hâlâ çok yaygın bir üretim tabanıdır.""");
74    }
75}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek4

çalıştırılabilir
Ornek4.java
1// Ornek4: JAVA 21 LTS — record patterns, sequenced collections, virtual threads (öncesi vs sonrası).
2// Çalıştırma: java Ornek4.java   (JDK 21 gerektirir)
3import java.util.ArrayList;
4import java.util.List;
5import java.util.concurrent.Executors;
6import java.util.concurrent.atomic.AtomicInteger;
7
8public class Ornek4 {
9
10    sealed interface Olay permits Tikla, Yaz {}
11    record Tikla(int x, int y) implements Olay {}
12    record Yaz(String metin) implements Olay {}
13
14    public static void main(String[] args) throws InterruptedException {
15        // ============ record patterns (Java 21): iç içe instanceof vs desen ayrıştırma ============
16        Olay olay = new Tikla(120, 45);
17
18        // ÖNCESİ (Java 16-17): instanceof + alanları elle çekme
19        String eski;
20        if (olay instanceof Tikla t) {
21            eski = "tık (" + t.x() + "," + t.y() + ")";
22        } else if (olay instanceof Yaz y) {
23            eski = "yaz: " + y.metin();
24        } else { eski = "?"; }
25
26        // SONRASI (Java 21): switch + RECORD PATTERN — alanlar doğrudan parçalanır
27        String yeni = switch (olay) {
28            case Tikla(int x, int y) -> "tık (" + x + "," + y + ")";
29            case Yaz(String m) -> "yaz: " + m;
30        };
31        System.out.println("record patterns (eski vs yeni): " + eski + " == " + yeni);
32
33        // ============ Sequenced Collections (Java 21): get(0)/get(size-1) vs getFirst/getLast ============
34        List<String> liste = new ArrayList<>(List.of("giriş", "işlem", "çıkış"));
35        // ESKİ
36        String ilkEski = liste.get(0);
37        String sonEski = liste.get(liste.size() - 1);
38        // YENİ (Java 21)
39        String ilkYeni = liste.getFirst();
40        String sonYeni = liste.getLast();
41        System.out.println("\nSequenced (eski vs yeni): ilk " + ilkEski + "/" + ilkYeni
42                + ", son " + sonEski + "/" + sonYeni);
43        System.out.println("reversed(): " + liste.reversed());
44
45        // ============ Virtual Threads (Java 21): platform thread vs sanal thread ============
46        System.out.println("\n--- 10.000 G/Ç görevi: platform vs sanal thread ---");
47        long platform = sureOlc(Executors.newFixedThreadPool(50));   // sınırlı havuz -> yavaş
48        long sanal = sureOlc(Executors.newVirtualThreadPerTaskExecutor()); // her göreve sanal thread
49        System.out.printf("Platform havuzu (50): ~%4d ms%n", platform);
50        System.out.printf("Sanal thread'ler   : ~%4d ms%n", sanal);
51
52        System.out.println("""
53
54                --- Java 21 LTS NE getirdi? ---
55                Virtual threads (yüksek eşzamanlılık), record patterns + switch pattern matching,
56                sequenced collections, generational ZGC. Çoğu projede 17->21 düşük riskli, yüksek kazançlı geçiştir.
57                (Java 22-25 için README'ye bak: FFM API, Stream Gatherers, sade main, modül import...)""");
58    }
59
60    static long sureOlc(java.util.concurrent.ExecutorService exec) throws InterruptedException {
61        AtomicInteger biten = new AtomicInteger();
62        long t0 = System.currentTimeMillis();
63        for (int i = 0; i < 10_000; i++) {
64            exec.submit(() -> {
65                try { Thread.sleep(10); } catch (InterruptedException ignored) {}
66                biten.incrementAndGet();
67            });
68        }
69        exec.shutdown();
70        exec.awaitTermination(60, java.util.concurrent.TimeUnit.SECONDS);
71        return System.currentTimeMillis() - t0;
72    }
73}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.