Eğitim Portalı/Java/Java 16 Yenilikleri (2021)
Java01-java/62-java16-yenilikleri

Java 16 Yenilikleri (2021)

Java 16, önceki sürümlerin iki büyük önizleme özelliğini standartlaştırdı: records ve pattern matching for instanceof. Ayrıca pratik stream eklemeleri (toList, mapMulti) getirdi. Bu, Java 17 LTS'e giden yolun son adım…

Java 16 Yenilikleri (2021)

Java 16, önceki sürümlerin iki büyük önizleme özelliğini standartlaştırdı: records ve pattern matching for instanceof. Ayrıca pratik stream eklemeleri (toList, mapMulti) getirdi. Bu, Java 17 LTS'e giden yolun son adımıydı — 17'de sealed sınıflar da standartlaşarak modern Java'nın çekirdek dil özellikleri tamamlandı.

records standart

Java 14-15'te önizleme olan record, Java 16'da standart oldu. Değişmez veri sınıflarını tek satıra indirir; equals/hashCode/toString ve getter'lar otomatik üretilir:

record Para(long kurus, String birim) {
    Para {                                  // kompakt kurucu: doğrulama/normalizasyon
        if (kurus < 0) throw new IllegalArgumentException("negatif olamaz");
        birim = birim.toUpperCase();
    }
    double tutar() { return kurus / 100.0; } // ek metot
    static Para tl(double t) { return new Para(Math.round(t*100), "TRY"); } // statik fabrika
}

Record'lar bir arayüz uygulayabilir, ek/statik metot içerebilir ve bir metot içinde yerel record olarak tanımlanabilir. Ama alan ekleyemez (durumu yalnızca bileşenleridir) ve başka sınıfı uzatamaz. Örnek 1 (./Ornek1.java) kompakt kurucu, statik fabrika, arayüz ve yerel record gösterir. (Records'ı topic 37/62'de ve veri modellemede sık kullanıyoruz; DTO/değer nesneleri için idealdir.)

pattern matching for instanceof standart

Java 14'te önizleme olan bu özellik Java 16'da standart oldu:

if (o instanceof String s) return s.length();   // kontrol + cast + bağlama tek adımda

Eski instanceof + ayrı cast kalıbını ortadan kaldırır. Örnek 2 (./Ornek2.java) bunu gösterir.

Stream eklentileri

  • Stream.toList(): collect(Collectors.toList()) için kısa yol. Değişmez bir liste döndürür (dikkat: eskisi değiştirilebilirdi).
  • Stream.mapMulti(fn): Her elemanı sıfır/bir/çok elemana genişletir — flatMap'e alternatif. Eleman başına az sayıda çıktı üretiliyorsa, ara Stream nesneleri oluşturmadığı için flatMap'ten daha verimli olabilir:
Stream.of(1,2,3).<Integer>mapMulti((n, tuket) -> { tuket.accept(n); tuket.accept(n*10); }).toList();
// [1, 10, 2, 20, 3, 30]

Örnek 2 her ikisini de gösterir.

Sürüm batch'inin sonu (8 → 16) ve sonrası

Bu konuyla, listenizdeki Java 8 → 16 sürüm-sürüm yenilikleri tamamlandı. Bu özelliklerin çoğu Java 17 (LTS) ve 21 (LTS) ile olgunlaştı:

  • Java 17 (LTS): sealed sınıflar standart.
  • Java 21 (LTS): record patterns, switch pattern matching, virtual threads, sequenced collections (topic 20 Ornek4'te gördük).

Yani 8-16 arası attığın her adım, bugünün modern Java'sının (17/21) temelini oluşturur.

Özet

Java 16'nın yeniliklerini öğrendik: standartlaşan records (kompakt kurucu, statik fabrika, yerel record; Örnek 1) ve pattern matching instanceof, ayrıca Stream.toList ve mapMulti (Örnek 2). Bununla sürüm-sürüm bölümü (Java 8→16) tamamlandı; bu özellikler 17/21 LTS'lerde olgunlaşarak modern Java'yı şekillendirdi. Sırada — bir sonraki büyük bölüm — Java'nın klasik GUI/web teknolojilerine giriş: Swing, AWT, Servlet, JSP.

Kod Örnekleri(2)

Ornek1

çalıştırılabilir
Ornek1.java
1// Ornek1: Java 16 — records STANDART (kompakt kurucu, statik fabrika, metot, arayüz).
2// Çalıştırma: java Ornek1.java
3public class Ornek1 {
4
5    interface Bilgilendirilebilir { String ozet(); }
6
7    // record: değişmez veri taşıyıcısı. equals/hashCode/toString/getter'lar OTOMATİK.
8    record Para(long kurus, String birim) implements Bilgilendirilebilir {
9
10        // KOMPAKT KURUCU: doğrulama/normalizasyon için (alan atamaları otomatik).
11        Para {
12            if (kurus < 0) throw new IllegalArgumentException("negatif tutar olamaz");
13            birim = birim.toUpperCase(); // normalize
14        }
15
16        // Ek (türetilmiş) metot
17        double tutar() { return kurus / 100.0; }
18
19        // Statik fabrika metodu
20        static Para tl(double t) { return new Para(Math.round(t * 100), "TRY"); }
21
22        // Arayüz metodu
23        @Override public String ozet() { return String.format("%.2f %s", tutar(), birim()); }
24    }
25
26    public static void main(String[] args) {
27        Para p1 = Para.tl(19.99);
28        Para p2 = new Para(1999, "try"); // birim normalize -> TRY
29        System.out.println("p1: " + p1 + " | ozet: " + p1.ozet());
30        System.out.println("p1.equals(p2)? " + p1.equals(p2) + " (değer eşitliği — otomatik)");
31        System.out.println("getter: kurus=" + p1.kurus() + ", birim=" + p1.birim());
32
33        try {
34            new Para(-5, "TRY");
35        } catch (IllegalArgumentException e) {
36            System.out.println("kompakt kurucu doğruladı: " + e.getMessage());
37        }
38
39        // Yerel (local) record — bir metot içinde geçici veri gruplamak için (Java 16).
40        record Nokta(int x, int y) {}
41        Nokta n = new Nokta(3, 4);
42        System.out.println("yerel record: " + n + ", uzaklık=" + Math.hypot(n.x(), n.y()));
43
44        System.out.println("""
45
46                --- Java 16: records standart ---
47                record, değişmez veri sınıflarını tek satıra indirir; equals/hashCode/toString/getter OTOMATİK.
48                Kompakt kurucu (Para { ... }): doğrulama ve normalizasyon için (alan atamaları örtük).
49                Ek metot, statik fabrika, arayüz uygulama desteklenir; YEREL record da olabilir.
50                (14-15'te önizleme, 16'da standart.) DTO/değer nesneleri için idealdir.""");
51    }
52}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.

Ornek2

çalıştırılabilir
Ornek2.java
1// Ornek2: Java 16 — pattern matching instanceof STANDART, Stream.toList() ve Stream.mapMulti.
2// Çalıştırma: java Ornek2.java
3import java.util.List;
4import java.util.stream.Stream;
5
6public class Ornek2 {
7
8    public static void main(String[] args) {
9        // 1) pattern matching for instanceof artık STANDART (Java 16).
10        Object[] nesneler = { "merhaba", 42, List.of(1, 2, 3), 3.14 };
11        for (Object o : nesneler) {
12            String s = tanim(o);
13            System.out.println(o + " -> " + s);
14        }
15
16        // 2) Stream.toList(): collect(Collectors.toList()) için kısa yol (değişmez liste döndürür).
17        List<Integer> kareler = Stream.of(1, 2, 3, 4).map(n -> n * n).toList();
18        System.out.println("\ntoList(): " + kareler);
19
20        // 3) Stream.mapMulti: her elemanı SIFIR/BİR/ÇOK elemana genişlet (flatMap'e alternatif, daha az nesne).
21        List<Integer> genisletilmis = Stream.of(1, 2, 3).<Integer>mapMulti((n, tuket) -> {
22            tuket.accept(n);        // elemanın kendisi
23            tuket.accept(n * 10);   // ve 10 katı
24        }).toList();
25        System.out.println("mapMulti (n ve 10n): " + genisletilmis);
26
27        System.out.println("""
28
29                --- Java 16: pattern matching standart, toList, mapMulti ---
30                pattern matching instanceof: 'if (o instanceof String s)' artık STANDART (önizleme değil).
31                Stream.toList(): .collect(Collectors.toList()) yerine kısa; DEĞİŞMEZ liste döndürür.
32                Stream.mapMulti(fn): her elemanı 0/1/çok elemana genişletir (flatMap benzeri ama daha az
33                  ara nesne üretir; eleman başına çok az çıktı varken daha verimli).""");
34    }
35
36    static String tanim(Object o) {
37        // pattern matching instanceof — kontrol + cast + bağlama tek adımda.
38        if (o instanceof String str) return "String(" + str.length() + ")";
39        if (o instanceof Integer i) return "Integer(kare=" + (i * i) + ")";
40        if (o instanceof List<?> liste) return "List(boyut=" + liste.size() + ")";
41        return o.getClass().getSimpleName();
42    }
43}
Çıktı yerel JDK 21 ile yakalandı — tarayıcıda JVM çalışmaz.