Java 16 (Mart 2021) — Detaylı Türkçe Dokümantasyon
| Özellik | Değer | |---|---| | Sürüm | Java SE 16 / JDK 16 | | Çıkış Tarihi | 16 Mart 2021 | | LTS mi? | HAYIR — kısa destekli ("feature release") sürümdür | | Destek Durumu | Java 17 (Eylül 2021) çıkınca destek sona…
Java 16 (Mart 2021) — Detaylı Türkçe Dokümantasyon
Sürüm Bilgisi
| Özellik | Değer |
|---|---|
| Sürüm | Java SE 16 / JDK 16 |
| Çıkış Tarihi | 16 Mart 2021 |
| LTS mi? | HAYIR — kısa destekli ("feature release") sürümdür |
| Destek Durumu | Java 17 (Eylül 2021) çıkınca destek sona erdi |
| Önemi | Java 17 LTS'e giden yolun son taşı. Records ve Pattern Matching burada kalıcı oldu |
Not: Java 16 üretimde uzun süre kullanılacak bir sürüm değildi. Asıl önemi, birçok modern dil özelliğini "preview"den çıkarıp stabil hale getirmesi ve hemen ardından gelen Java 17 LTS için zemin hazırlamasıdır.
Genel Bakış — Bu Sürümde Neler Var?
| Özellik | Durum | Dosya |
|---|---|---|
| Records (Kayıtlar) | Kalıcı | RecordsKalici.java |
Pattern Matching for instanceof | Kalıcı | PatternMatchingKalici.java |
Stream.toList() | Kalıcı | StreamToList.java |
| Sealed Classes | İkinci Preview | (Java 17'de kalıcı — 10-Java-17/) |
| Day Period Support | Kalıcı | — (aşağıda anlatılır) |
| JDK Internals'ın güçlü kapsüllenmesi | Varsayılan açık | — (geçiş riski!) |
| Unix-Domain Socket Channels | Kalıcı | — (aşağıda anlatılır) |
| Foreign Linker API | Incubator | — (deneysel) |
1) Records (Kayıtlar) — KALICI
Dosya: RecordsKalici.java
NEDİR?
Yalnızca veri taşıyan (data carrier) değişmez (immutable) sınıflar için gelen özel bir sınıf türü. record Nokta(int x, int y) {} tek satırı; private final alanları, constructor'ı, erişimcileri (x(), y()), equals(), hashCode() ve toString() metotlarını otomatik üretir.
NEDEN GELDİ?
Java'da on yıllardır yazdığımız DTO/POJO sınıfları aşırı tekrar eden kod (boilerplate) içeriyordu. İki alanlık bir sınıf için bile 40+ satır yazmak gerekiyordu. Records bunu ortadan kaldırır.
NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR?
- API request/response (DTO) modelleri
- Map anahtarları (
equals/hashCodehazır gelir) - Stream pipeline'larında ara veri yapıları
- Sealed Classes + Pattern Matching ile birlikte cebirsel veri tipleri (bkz. Java 17)
ESKİ vs YENİ
// ESKİ: ~40 satır (alanlar, ctor, getterlar, equals, hashCode, toString) final class KlasikNokta { private final int x; ... } // YENİ: tek satır record Nokta(int x, int y) {}
Records'ta Neler Yapılabilir / Yapılamaz?
- Yapılabilir: compact constructor (doğrulama), custom/static metotlar, interface implement, generic record, accessor override, nested/local record.
- Yapılamaz:
extendsile türetilmek/türetmek (record örtükfinal), ek instance alanı eklemek, alanları mutable yapmak.
Gerçek Hayat
RecordsKalici.java içinde e-ticaret SiparisOzeti örneği: iç içe record'lar, compact constructor ile savunmacı kopya (List.copyOf), ve toplamTutar() gibi hesaplanmış metotlar gösterilir.
2) Pattern Matching for instanceof — KALICI
Dosya: PatternMatchingKalici.java
NEDİR?
if (o instanceof String s) ifadesiyle tip kontrolü, cast ve değişkene atamayı tek adımda birleştirir.
ESKİ vs YENİ
// ESKİ: 3 adım if (o instanceof String) { String s = (String) o; // ayrı cast use(s); } // YENİ: tek satır, cast yok if (o instanceof String s) { use(s); }
NEREDE KOLAYLIK SAĞLAR?
equals()metotlarını sadeleştirir- Karışık tipli (heterojen) verilerde tip yönlendirmesi
&&ile koşul birleştirme:if (o instanceof String s && s.length() > 5)
3) Stream.toList() — KALICI
Dosya: StreamToList.java
NEDİR / NEDEN GELDİ?
Bir stream'i listeye çevirmenin kısa yolu. Artık .collect(Collectors.toList()) yerine doğrudan .toList().
ESKİ vs YENİ
// ESKİ list.stream().filter(...).collect(Collectors.toList()); // YENİ list.stream().filter(...).toList();
ÖNEMLİ FARK
.toList() değişmez (unmodifiable) liste döndürür. add/remove denenirse UnsupportedOperationException fırlatır. Eğer sonradan değiştirmeniz gerekiyorsa eski yöntemi (veya Collectors.toCollection(ArrayList::new)) kullanın.
4) Day Period Support (JDK-8247781)
DateTimeFormatter artık günün bölümlerini ("sabah", "öğleden sonra", "akşam", "gece") biçimlendirebilir (B deseni). CLDR verisine dayanır. Yerelleştirilmiş, insan-dostu zaman gösterimi sağlar.
5) JDK Internals'ın Güçlü Kapsüllenmesi (Strong Encapsulation) — GEÇİŞ RİSKİ!
- Java 9'dan beri uyarı verilen iç API'lere (
sun.misc.Unsafe, dahili paketler) erişim Java 16'da varsayılan olarak engellendi. --illegal-access=permitartık varsayılan değil; reflection ile dahili sınıflara erişen eski kütüphaneler bozulabilir.- Risk: Eski Hibernate, eski Mockito, bazı serileştirme kütüphaneleri çalışmayabilir. Geçici çözüm
--add-opensbayrakları; kalıcı çözüm kütüphaneleri güncellemek. sun.misc.Unsafegibi kritik API'ler hâlâ erişilebilir kaldı ama bu eğilim kapanma yönündedir.
6) Unix-Domain Socket Channels (JEP 380)
SocketChannel / ServerSocketChannel artık Unix-domain soketlerini destekler. Aynı makinedeki süreçler arası iletişimde (IPC) TCP/IP'ye göre daha hızlı ve güvenlidir (örn. veritabanı/uygulama sunucusu aynı makinedeyse).
7) Foreign Linker API (JEP 389) — Incubator (Deneysel)
JNI'a modern, güvenli bir alternatif: Java'dan yerel (native) C kütüphanelerini çağırma. Henüz deneysel; ilerleyen sürümlerde "Foreign Function & Memory API" olarak olgunlaştı.
Java 8/11'den Geçiş Notları
- Avantaj: Records ve pattern matching artık stabil — kod tabanınızı sadeleştirin.
- Risk: Güçlü kapsülleme nedeniyle dahili API'lere dayanan eski bağımlılıklar kırılabilir. Önce bağımlılıkları güncelleyin,
--add-opens'ı geçici çözüm olarak kullanın. - Öneri: Java 16'da kalmayın; Java 17 LTS'e geçin. Java 16'daki tüm kalıcı özellikler 17'de de vardır, üstüne LTS güvencesi gelir.
Bu Klasördeki Dosyalar
RecordsKalici.java— Records'ın derinlemesine kullanımıPatternMatchingKalici.java—instanceofkalıp eşleştirmeStreamToList.java—Stream.toList()
Derleme ve Çalıştırma
javac RecordsKalici.java && java RecordsKalici javac PatternMatchingKalici.java && java PatternMatchingKalici javac StreamToList.java && java StreamToList
▶ Kod Örnekleri(3)
PatternMatchingKalici
çalıştırılabilir1// =============================================================================
2// PatternMatchingKalici.java
3// JAVA 16 - Pattern Matching for instanceof ARTIK KALICI (FINAL)
4// =============================================================================
5//
6// NEDİR?
7// "instanceof için kalıp eşleştirme", bir nesnenin tipini kontrol ederken
8// AYNI ANDA o tipte bir değişkene atamayı (binding) sağlar. Java 14'te
9// preview, Java 15'te ikinci preview, JAVA 16 ile KALICI hale geldi.
10//
11// NEDEN GELDİ / NE İŞE YARAR?
12// Klasik yaklaşımda her zaman ŞU üç adımı yapardık:
13// 1) instanceof ile tip kontrolü
14// 2) açıkça (explicit) cast
15// 3) yeni bir değişkene atama
16// Bu hem tekrar (boilerplate) hem de cast hatasına açık bir kalıptı.
17// Pattern matching bu üç adımı TEK İFADEDE birleştirir.
18//
19// Derlemek için: javac PatternMatchingKalici.java
20// Çalıştırmak : java PatternMatchingKalici
21// =============================================================================
22
23import java.util.List;
24
25public class PatternMatchingKalici {
26
27 public static void main(String[] args) {
28
29 System.out.println("=== JAVA 16: Pattern Matching for instanceof (KALICI) ===\n");
30
31 // ---------------------------------------------------------------------
32 // 1) ESKİ YÖNTEM vs YENİ YÖNTEM
33 // ---------------------------------------------------------------------
34 Object nesne = "Merhaba Java 16";
35
36 // ESKİ: kontrol + cast + atama (3 adım)
37 System.out.println("--- ESKİ yöntem ---");
38 if (nesne instanceof String) {
39 String s = (String) nesne; // ayrı cast satırı
40 System.out.println("Uzunluk (eski): " + s.length());
41 }
42
43 // YENİ: instanceof içinde "s" bağlanır (binding variable)
44 System.out.println("--- YENİ yöntem ---");
45 if (nesne instanceof String s) { // cast otomatik, s hazır
46 System.out.println("Uzunluk (yeni): " + s.length());
47 }
48 System.out.println();
49
50 // ---------------------------------------------------------------------
51 // 2) KOŞULLARLA BİRLEŞTİRME (binding değişkeni && ile kullanılabilir)
52 // ---------------------------------------------------------------------
53 System.out.println("--- Koşulla birleştirme ---");
54 Object veri = "kurumsal";
55 if (veri instanceof String s && s.length() > 5) {
56 // s hem cast edilmiş hem de uzunluk kontrolünden geçmiş halde
57 System.out.println("Uzun metin: " + s.toUpperCase());
58 }
59
60 // Negatif kontrolde (scope flow) binding değişkeni dışarıda da kullanılabilir:
61 if (!(veri instanceof String s2)) {
62 System.out.println("String değil");
63 } else {
64 // else dalında s2 erişilebilir çünkü buraya ancak String ise gelinir
65 System.out.println("else dalında erişilebilir: " + s2);
66 }
67 System.out.println();
68
69 // ---------------------------------------------------------------------
70 // 3) GERÇEK HAYAT: equals() metodu yazmak çok kolaylaşır
71 // ---------------------------------------------------------------------
72 System.out.println("--- Gerçek hayat: equals() implementasyonu ---");
73 var p1 = new Personel(1, "Ali");
74 var p2 = new Personel(1, "Ali");
75 var p3 = new Personel(2, "Veli");
76 System.out.println("p1.equals(p2): " + p1.equals(p2)); // true
77 System.out.println("p1.equals(p3): " + p1.equals(p3)); // false
78 System.out.println();
79
80 // ---------------------------------------------------------------------
81 // 4) GERÇEK HAYAT: heterojen listede tip-bazlı işlem
82 // ---------------------------------------------------------------------
83 System.out.println("--- Gerçek hayat: karışık tipli liste işleme ---");
84 List<Object> kayitlar = List.of(
85 "metin verisi",
86 42,
87 3.14,
88 List.of("a", "b", "c")
89 );
90
91 for (Object kayit : kayitlar) {
92 String aciklama = acikla(kayit);
93 System.out.println(" " + aciklama);
94 }
95 }
96
97 // Pattern matching ile sade, okunabilir tip yönlendirmesi
98 static String acikla(Object o) {
99 if (o instanceof String s) {
100 return "Metin (" + s.length() + " karakter): " + s;
101 } else if (o instanceof Integer i) {
102 return "Tam sayı, karesi = " + (i * i);
103 } else if (o instanceof Double d) {
104 return "Ondalık, yuvarlanmış = " + Math.round(d);
105 } else if (o instanceof List<?> liste) {
106 return "Liste (" + liste.size() + " eleman)";
107 }
108 return "Bilinmeyen tip";
109 }
110
111 // =========================================================================
112 // GERÇEK HAYAT: equals() yazarken pattern matching kullanımı
113 // =========================================================================
114 static final class Personel {
115 private final int id;
116 private final String ad;
117
118 Personel(int id, String ad) {
119 this.id = id;
120 this.ad = ad;
121 }
122
123 @Override
124 public boolean equals(Object o) {
125 // ESKİ yöntemde:
126 // if (!(o instanceof Personel)) return false;
127 // Personel that = (Personel) o;
128 // return ...
129 // YENİ yöntemde tek satırda kontrol + cast + binding:
130 return o instanceof Personel p
131 && this.id == p.id
132 && this.ad.equals(p.ad);
133 }
134
135 @Override
136 public int hashCode() {
137 return id * 31 + ad.hashCode();
138 }
139 }
140}RecordsKalici
çalıştırılabilir1// =============================================================================
2// RecordsKalici.java
3// JAVA 16 - Records (Kayıtlar) ARTIK KALICI (FINAL) ÖZELLİK
4// =============================================================================
5//
6// Records, Java 14'te preview olarak geldi, Java 15'te ikinci preview oldu
7// ve JAVA 16 ile birlikte KALICI (stabil) hale geldi. Artık preview bayrağı
8// olmadan üretimde güvenle kullanılabilir.
9//
10// NEDİR?
11// Record, "sadece veri taşıyan" (data carrier) sınıflar yazmak için gelen
12// özel bir sınıf türüdür. Java'da on yıllardır yazdığımız "POJO" / "DTO"
13// sınıflarındaki tekrar eden kalıp kod (boilerplate) ortadan kalkar:
14// - private final alanlar
15// - constructor
16// - getter metotları (record'da alanAdi() şeklinde)
17// - equals(), hashCode()
18// - toString()
19// Bunların hepsi derleyici tarafından OTOMATİK üretilir.
20//
21// Derlemek için (Java 16+): javac RecordsKalici.java
22// Çalıştırmak için: java RecordsKalici
23// =============================================================================
24
25import java.util.List;
26import java.util.Objects;
27
28public class RecordsKalici {
29
30 public static void main(String[] args) {
31
32 System.out.println("=== JAVA 16: RECORDS KALICI ÖZELLİK ===\n");
33
34 // ---------------------------------------------------------------------
35 // 1) ESKİ YÖNTEM vs YENİ YÖNTEM
36 // ---------------------------------------------------------------------
37 System.out.println("--- 1) Eski POJO vs Record karşılaştırması ---");
38
39 // Eski yöntemde (aşağıdaki KlasikNokta sınıfına bakın) onlarca satır yazardık.
40 KlasikNokta kn1 = new KlasikNokta(3, 4);
41 KlasikNokta kn2 = new KlasikNokta(3, 4);
42 System.out.println("Klasik POJO toString : " + kn1);
43 System.out.println("Klasik POJO equals : " + kn1.equals(kn2));
44
45 // Yeni yöntem: TEK SATIR (aşağıdaki Nokta record'una bakın)
46 Nokta n1 = new Nokta(3, 4);
47 Nokta n2 = new Nokta(3, 4);
48 System.out.println("Record toString : " + n1); // Otomatik
49 System.out.println("Record equals : " + n1.equals(n2)); // Otomatik (true)
50 System.out.println("Record hashCode eşit : " + (n1.hashCode() == n2.hashCode()));
51 System.out.println("Record getter (x) : " + n1.x()); // getX() değil, x()
52 System.out.println();
53
54 // ---------------------------------------------------------------------
55 // 2) COMPACT CONSTRUCTOR (Sıkıştırılmış Yapıcı) ile DOĞRULAMA
56 // ---------------------------------------------------------------------
57 System.out.println("--- 2) Compact constructor ile doğrulama ---");
58 try {
59 // Geçerli bir aralık
60 TarihAraligi gecerli = new TarihAraligi(1, 10);
61 System.out.println("Geçerli aralık oluşturuldu: " + gecerli);
62
63 // Geçersiz aralık -> compact constructor exception fırlatır
64 TarihAraligi gecersiz = new TarihAraligi(10, 1);
65 System.out.println(gecersiz); // buraya ulaşılmaz
66 } catch (IllegalArgumentException e) {
67 System.out.println("Doğrulama hatası yakalandı: " + e.getMessage());
68 }
69 System.out.println();
70
71 // ---------------------------------------------------------------------
72 // 3) RECORD İÇİNDE CUSTOM METOT, STATIC METOT, EK CONSTRUCTOR
73 // ---------------------------------------------------------------------
74 System.out.println("--- 3) Record'a ek davranış eklemek ---");
75 Para tl = Para.lira(150.0); // static factory metodu
76 Para indirimli = tl.indirimUygula(0.20); // custom örnek metodu
77 System.out.println("Orijinal fiyat : " + tl.formatli());
78 System.out.println("İndirimli fiyat: " + indirimli.formatli());
79 System.out.println();
80
81 // ---------------------------------------------------------------------
82 // 4) GERÇEK HAYAT: API yanıtı / veri taşıma nesnesi olarak record
83 // ---------------------------------------------------------------------
84 System.out.println("--- 4) Gerçek hayat: bir e-ticaret sipariş özeti ---");
85 var siparis = new SiparisOzeti(
86 "SP-2026-0042",
87 "Ahmet Yılmaz",
88 List.of(
89 new SiparisKalemi("Klavye", 2, 450.0),
90 new SiparisKalemi("Mouse", 1, 250.0)
91 )
92 );
93 System.out.println("Sipariş No : " + siparis.siparisNo());
94 System.out.println("Müşteri : " + siparis.musteriAdi());
95 System.out.println("Kalem sayısı: " + siparis.kalemler().size());
96 System.out.println("Toplam tutar: " + siparis.toplamTutar() + " TL");
97 System.out.println();
98
99 // ---------------------------------------------------------------------
100 // 5) İÇ İÇE (NESTED) RECORD ve LOCAL RECORD
101 // ---------------------------------------------------------------------
102 System.out.println("--- 5) Local record (metot içinde tanımlı) ---");
103 // Java 16 ile metot içinde bile record tanımlanabilir (local record).
104 record Cift(String ad, int puan) {}
105 var ogrenciler = List.of(
106 new Cift("Zeynep", 95),
107 new Cift("Mehmet", 80)
108 );
109 ogrenciler.forEach(o ->
110 System.out.println(" " + o.ad() + " -> " + o.puan()));
111 System.out.println();
112
113 System.out.println("=== Records, veri modellemeyi sade ve güvenli kılar. ===");
114 }
115
116 // =========================================================================
117 // ESKİ YÖNTEM: Klasik POJO (boilerplate dolu)
118 // Sadece 2 alan için ~40 satır kod gerekiyor!
119 // =========================================================================
120 static final class KlasikNokta {
121 private final int x;
122 private final int y;
123
124 KlasikNokta(int x, int y) {
125 this.x = x;
126 this.y = y;
127 }
128
129 public int getX() { return x; }
130 public int getY() { return y; }
131
132 @Override
133 public boolean equals(Object o) {
134 if (this == o) return true;
135 if (o == null || getClass() != o.getClass()) return false;
136 KlasikNokta that = (KlasikNokta) o;
137 return x == that.x && y == that.y;
138 }
139
140 @Override
141 public int hashCode() {
142 return Objects.hash(x, y);
143 }
144
145 @Override
146 public String toString() {
147 return "KlasikNokta{x=" + x + ", y=" + y + '}';
148 }
149 }
150
151 // =========================================================================
152 // YENİ YÖNTEM: Aynı işi yapan record - TEK SATIR
153 // - x ve y "components" (bileşen) olarak adlandırılır.
154 // - Otomatik: private final alanlar, canonical constructor,
155 // x()/y() erişimcileri, equals/hashCode/toString.
156 // =========================================================================
157 record Nokta(int x, int y) {}
158
159 // =========================================================================
160 // COMPACT CONSTRUCTOR örneği
161 // - Parametre listesi YAZILMAZ; sadece doğrulama/normalizasyon yapılır.
162 // - Atama (this.baslangic = baslangic) otomatik eklenir.
163 // =========================================================================
164 record TarihAraligi(int baslangic, int bitis) {
165 TarihAraligi { // <-- compact constructor: parantez yok!
166 if (baslangic > bitis) {
167 throw new IllegalArgumentException(
168 "baslangic (" + baslangic + ") bitisten (" + bitis + ") büyük olamaz");
169 }
170 }
171 }
172
173 // =========================================================================
174 // Record içinde: custom metot + static factory + ek davranış
175 // Record'lar IMMUTABLE (değişmez) olduğundan, "değiştirme" metotları
176 // YENİ bir record örneği döndürür (with-pattern).
177 // =========================================================================
178 record Para(double tutar, String birim) {
179
180 // Static factory metodu
181 static Para lira(double tutar) {
182 return new Para(tutar, "TL");
183 }
184
185 // Custom örnek metodu: yeni Para döndürür (immutability korunur)
186 Para indirimUygula(double oran) {
187 return new Para(tutar * (1 - oran), birim);
188 }
189
190 // Formatlama yardımcı metodu
191 String formatli() {
192 return String.format("%.2f %s", tutar, birim);
193 }
194 }
195
196 // =========================================================================
197 // GERÇEK HAYAT: iç içe record'lar + hesaplanmış (derived) değer
198 // =========================================================================
199 record SiparisKalemi(String urunAdi, int adet, double birimFiyat) {
200 double araToplam() {
201 return adet * birimFiyat;
202 }
203 }
204
205 record SiparisOzeti(String siparisNo, String musteriAdi, List<SiparisKalemi> kalemler) {
206
207 // Compact constructor ile defensive copy (savunmacı kopya)
208 // Record bileşeni List ise dıştan değiştirilmemesi için kopyalanır.
209 SiparisOzeti {
210 kalemler = List.copyOf(kalemler); // değişmez kopya
211 }
212
213 // Hesaplanmış toplam tutar (alan değil, metot)
214 double toplamTutar() {
215 return kalemler.stream()
216 .mapToDouble(SiparisKalemi::araToplam)
217 .sum();
218 }
219 }
220}
221
222// =============================================================================
223// ÖNEMLİ NOTLAR — RECORD'LARDA NELER YAPILABİLİR / YAPILAMAZ
224// =============================================================================
225//
226// YAPILABİLİR:
227// - Custom örnek metotları, static metotlar, static alanlar eklemek
228// - Compact constructor veya ek (overloaded) constructor tanımlamak
229// - Interface implement etmek (implements)
230// - Generic record tanımlamak: record Kutu<T>(T deger) {}
231// - Otomatik erişimcileri (accessor) override etmek
232// - Annotation kullanmak
233// - Nested ve local record tanımlamak
234//
235// YAPILAMAZ:
236// - Başka bir sınıftan extends ile türetmek (record örtük olarak final ve
237// java.lang.Record'tan türer)
238// - Record'u extends ile genişletmek (record örtük final'dır)
239// - Ek instance (örnek) alanı eklemek (tüm state, bileşenlerle tanımlanır)
240// - Bileşenlere ait alanları mutable yapmak (hepsi private final'dır)
241//
242// NEREDE KOLAYLIK SAĞLAR:
243// - DTO / API request-response modelleri
244// - Map anahtarları (equals/hashCode hazır)
245// - Stream pipeline'larında ara veri yapıları
246// - Sealed sınıflarla birlikte "algebraic data types" (Java 17 örneklerine bakın)
247// =============================================================================StreamToList
çalıştırılabilir1// =============================================================================
2// StreamToList.java
3// JAVA 16 - Stream.toList() metodu
4// =============================================================================
5//
6// NEDİR?
7// Java 16 ile Stream arayüzüne doğrudan toList() metodu eklendi. Bir stream'i
8// List'e dönüştürmenin en kısa yolu artık budur.
9//
10// NEDEN GELDİ?
11// Java 8'den beri stream'i listeye çevirmek için
12// .collect(Collectors.toList())
13// yazmak zorundaydık. Bu hem uzun hem de:
14// - Collectors sınıfını import etmeyi gerektiriyordu,
15// - Dönen listenin mutable/immutable olup olmadığı GARANTİ değildi
16// (implementasyona bağlıydı, genelde ArrayList dönerdi).
17// Stream.toList() ise DEĞİŞMEZ (unmodifiable) bir liste döndürür ve daha sade.
18//
19// Derlemek için: javac StreamToList.java
20// Çalıştırmak : java StreamToList
21// =============================================================================
22
23import java.util.List;
24import java.util.stream.Collectors;
25import java.util.stream.Stream;
26
27public class StreamToList {
28
29 public static void main(String[] args) {
30
31 System.out.println("=== JAVA 16: Stream.toList() ===\n");
32
33 var sayilar = List.of(5, 12, 8, 130, 44, 3);
34
35 // ---------------------------------------------------------------------
36 // ESKİ YÖNTEM (Java 8 - 15): Collectors.toList()
37 // ---------------------------------------------------------------------
38 List<Integer> eski = sayilar.stream()
39 .filter(s -> s > 10)
40 .map(s -> s * 2)
41 .collect(Collectors.toList()); // uzun, import gerektirir
42 System.out.println("ESKİ (collect(Collectors.toList())): " + eski);
43
44 // ---------------------------------------------------------------------
45 // YENİ YÖNTEM (Java 16+): Stream.toList()
46 // ---------------------------------------------------------------------
47 List<Integer> yeni = sayilar.stream()
48 .filter(s -> s > 10)
49 .map(s -> s * 2)
50 .toList(); // kısa, import yok, immutable
51 System.out.println("YENİ (toList()) : " + yeni);
52 System.out.println();
53
54 // ---------------------------------------------------------------------
55 // ÖNEMLİ FARK: toList() DEĞİŞMEZ (unmodifiable) liste döndürür
56 // ---------------------------------------------------------------------
57 System.out.println("--- toList() değişmezdir ---");
58 try {
59 yeni.add(999); // UnsupportedOperationException fırlatır
60 } catch (UnsupportedOperationException e) {
61 System.out.println("toList() listesine ekleme yapılamaz (immutable). OK.");
62 }
63
64 // collect(Collectors.toList()) genelde MUTABLE ArrayList döner:
65 eski.add(999);
66 System.out.println("collect(toList()) listesine eklenebildi: " + eski);
67 System.out.println();
68
69 // ---------------------------------------------------------------------
70 // GERÇEK HAYAT: Bir kullanıcı listesinden aktif olanların adlarını çıkarma
71 // ---------------------------------------------------------------------
72 System.out.println("--- Gerçek hayat senaryosu ---");
73 record Kullanici(String ad, boolean aktif) {}
74
75 var kullanicilar = List.of(
76 new Kullanici("Ayşe", true),
77 new Kullanici("Burak", false),
78 new Kullanici("Cem", true),
79 new Kullanici("Deniz", true)
80 );
81
82 List<String> aktifAdlar = kullanicilar.stream()
83 .filter(Kullanici::aktif)
84 .map(Kullanici::ad)
85 .sorted()
86 .toList();
87
88 System.out.println("Aktif kullanıcılar: " + aktifAdlar);
89 System.out.println();
90
91 // ---------------------------------------------------------------------
92 // NE ZAMAN ESKİ YÖNTEMİ KULLANMALI?
93 // - Eğer dönen listeyi SONRADAN değiştirmeniz gerekiyorsa
94 // (add/remove), o zaman collect(Collectors.toList()) veya
95 // collect(Collectors.toCollection(ArrayList::new)) kullanın.
96 // - Aksi halde her zaman .toList() tercih edin: kısa ve güvenli.
97 // ---------------------------------------------------------------------
98 Stream<String> harfler = Stream.of("c", "a", "b");
99 System.out.println("Sıralı liste: " + harfler.sorted().toList());
100 }
101}