Java 12 (Mart 2019) — Detaylı Sürüm Analizi
> Çıkış Tarihi: 19 Mart 2019 > Sürüm Tipi: Standart (feature) sürüm — LTS DEĞİL > Destek Modeli: Java 12, 6 aylık sürüm döngüsünün bir parçasıdır. Java 13 (Eylül 2019) çıktığında resmî destek bitmiştir. Yani Java 12 k…
Java 12 (Mart 2019) — Detaylı Sürüm Analizi
Çıkış Tarihi: 19 Mart 2019 Sürüm Tipi: Standart (feature) sürüm — LTS DEĞİL Destek Modeli: Java 12, 6 aylık sürüm döngüsünün bir parçasıdır. Java 13 (Eylül 2019) çıktığında resmî destek bitmiştir. Yani Java 12 kısa ömürlü bir "ara sürümdür"; üretimde uzun süre kalması beklenmez. Bu sürümdeki kalıcı özellikler sonraki LTS olan Java 17'ye taşınmıştır.
İçindekiler
- Genel Bakış
- Java 11'den Java 12'ye Geçişte Ne Değişti?
- Özellik 1: Switch Expressions (Preview)
- Özellik 2: Compact Number Formatting
- Özellik 3: Teeing Collector
- Özellik 4: Shenandoah GC (Deneysel)
- Özellik 5: JVM Constants API
- Preview → Kalıcı Evrimi
- Avantaj / Dezavantaj / Risk Tablosu
- Dosya Listesi
Genel Bakış
Java 12, 6 aylık hızlı sürüm modelinin üçüncü adımıdır (Java 9 → 10 → 11 → 12). Java 11 büyük bir LTS sürümüydü; Java 12 ise daha çok geliştirici ergonomisi (kod yazma kolaylığı) ve çöp toplayıcı (GC) iyileştirmeleri üzerine odaklandı.
Bu sürümün en dikkat çeken yeniliği, ilk kez "Preview Feature" (önizleme özelliği) kavramının uygulamaya konmasıdır. Switch Expressions bu mekanizmayla geldi: özellik tam olgunlaşmadan önce topluluğun denemesi ve geri bildirim vermesi sağlandı.
Java 12'de gelen başlıca yenilikler:
| # | Özellik | JEP / Tip | Durum (Java 12'de) |
|---|---|---|---|
| 1 | Switch Expressions | JEP 325 | Preview (önizleme) |
| 2 | Compact Number Formatting | JDK-8188147 | Kalıcı |
| 3 | Teeing Collector | JDK-8209685 | Kalıcı |
| 4 | Shenandoah GC | JEP 189 | Deneysel (Experimental) |
| 5 | JVM Constants API | JEP 334 | Kalıcı |
| 6 | Default CDS Archives | JEP 341 | Kalıcı (performans) |
| 7 | Abortable Mixed Collections for G1 | JEP 344 | Kalıcı (G1 iyileştirme) |
| 8 | Promptly Return Unused Committed Memory from G1 | JEP 346 | Kalıcı (G1 iyileştirme) |
Bu dokümanda istenen 5 ana özellik (1–5) detaylandırılmıştır.
Java 11'den Java 12'ye Geçişte Ne Değişti?
| Konu | Java 11 | Java 12 |
|---|---|---|
switch | Yalnızca klasik statement (deyim), break zorunlu, fall-through riski | Yeni expression söz dizimi (->, yield) — preview olarak eklendi |
| Sayı kısaltma | El ile bölme + string birleştirme | NumberFormat.getCompactNumberInstance() ile dile duyarlı kısaltma |
| Stream'den çoklu özet | İki ayrı stream geçişi veya özel collector | Collectors.teeing() ile tek geçişte iki sonuç |
| Düşük gecikmeli GC | ZGC (deneysel, JDK 11) | ZGC + Shenandoah (deneysel olarak eklendi) |
| Dinamik sabitler | Yok | java.lang.constant paketi (JVM Constants API) |
| Başlangıç hızı | CDS arşivi manuel oluşturulmalı | Varsayılan CDS arşivi ile daha hızlı başlangıç |
Geçiş notu: Java 11 → 12 geçişi çoğu uygulama için kaynak-uyumludur (source-compatible). Var olan kod büyük ihtimalle değişiklik gerektirmeden derlenir. Tek dikkat edilecek nokta, eğer preview özellik (Switch Expressions) kullanacaksanız --enable-preview bayrağının gerekmesidir.
Özellik 1: Switch Expressions (Preview)
İlgili dosya:
SwitchExpressionsPreview.java
NEDİR?
switch yapısının, bir deyim (statement) olmanın yanı sıra artık bir ifade (expression) olarak da kullanılabilmesidir; yani doğrudan bir değer üretip döndürebilir. Yeni söz dizimi -> (ok) operatörünü, çoklu case etiketlerini (case 1, 2, 3 ->) ve çok satırlı bloklarda değer döndürmek için yield anahtar sözcüğünü getirir.
NEDEN GELDİ? (Hangi problemi çözüyor)
Klasik switch üç büyük sorun barındırıyordu:
- Fall-through riski: Her
casesonundabreakyazmayı unutmak, sessiz ve bulunması zor bir hataya yol açar. - Değer üretememe:
switchdoğrudan değer döndüremediği için, her seferinde ekstra bir değişken tanımlayıp her case içinde ona atama yapmak gerekirdi (gürültülü, tekrarlı kod). - Eksik kapsama uyarısı yok: Klasik
switchtüm durumların ele alındığını derleme zamanında kontrol etmez.
NE İŞE YARAR?
breakihtiyacını ortadan kaldırır → fall-through hatası imkânsız hale gelir.switch'i sağ tarafa yazıp doğrudan bir değişkene atayabilirsiniz:int x = switch(...) { ... };- Birden çok etiketi tek satırda gruplayabilirsiniz:
case PAZARTESI, SALI, CARSAMBA -> ...
NEREDE KOLAYLIK SAĞLAR?
Çok dallı eşleme (mapping) mantıklarında: enum → davranış, HTTP kodu → mesaj, gün → çalışma saati, durum makineleri (state machine). Kod daha kısa, daha okunur ve daha güvenli olur.
ESKİ vs YENİ Kod Karşılaştırması
ESKİ (Java 11 ve öncesi — statement):
int calismaSaati; switch (gun) { case 1: case 2: case 3: case 4: case 5: calismaSaati = 8; break; // <-- unutulursa fall-through! case 6: calismaSaati = 4; break; case 7: calismaSaati = 0; break; default: calismaSaati = -1; }
YENİ (Java 12 preview — expression):
int calismaSaati = switch (gun) { case 1, 2, 3, 4, 5 -> 8; // coklu case, break yok case 6 -> 4; case 7 -> 0; default -> -1; }; // <-- expression, sonunda ';'
Çok satırlı işlem gerektiğinde yield:
String aciklama = switch (gun) { case 6 -> { int saat = 4; yield "Cumartesi - " + saat + " saat"; // yield ile deger dondur } default -> "Diger"; };
GERÇEK HAYAT ÖRNEĞİ
Bir REST API'de gelen HTTP durum kodunu kullanıcıya gösterilecek Türkçe mesaja çevirmek (200 → "Başarılı", 404 → "Bulunamadı", 500 → "Sunucu hatası"). Tek switch ifadesiyle, ekstra değişken ve break olmadan temiz bir şekilde çözülür. Detaylı çalışan örnek için SwitchExpressionsPreview.java dosyasına bakın.
Derleme Notu (PREVIEW)
Java 12'de bu özellik preview olduğu için:
javac --release 12 --enable-preview SwitchExpressionsPreview.java java --enable-preview SwitchExpressionsPreview
Java 14+ (örn. sisteminizdeki Java 21) ile özellik kalıcı olduğundan hiçbir bayrak gerekmeden derlenir.
Özellik 2: Compact Number Formatting
İlgili dosya:
CompactNumberFormat.java
NEDİR?
NumberFormat.getCompactNumberInstance(Locale, Style) ile büyük sayıları kısa, insan-dostu biçimde gösterme yeteneğidir. 1000 → "1K", 1000000 → "1M" gibi. İki stil vardır: SHORT ("1K") ve LONG ("1 thousand").
NEDEN GELDİ? (Hangi problemi çözüyor)
Sosyal medya beğeni sayısı, takipçi, görüntülenme, dosya boyutu gibi değerleri "1.2K", "3.4M" şeklinde göstermek çok yaygındır. Önceden bunu el ile yapmak gerekiyordu ve bu yaklaşım:
- Dile duyarlı değildi (Türkçe'de "bin/milyon", İngilizce'de "K/M" gerekir),
- yuvarlama ve çoğullaşma kurallarını yanlış yönetiyordu,
- her projede yeniden yazılıyordu (kod tekrarı).
NE İŞE YARAR?
Sayıyı, verdiğiniz locale'in (dilin) kurallarına göre otomatik olarak kısaltır ve doğru eki (K/M/B veya bin/milyon/milyar) seçer.
NEREDE KOLAYLIK SAĞLAR?
Dashboard/istatistik ekranları, sosyal medya uygulamaları, analitik panelleri, dosya yöneticileri, uluslararası (i18n) uygulamalar.
ESKİ vs YENİ Kod Karşılaştırması
ESKİ:
String kisalt(long sayi) { if (sayi < 1_000) return String.valueOf(sayi); else if (sayi < 1_000_000) return (sayi / 1_000) + "K"; else if (sayi < 1_000_000_000) return (sayi / 1_000_000) + "M"; else return (sayi / 1_000_000_000) + "B"; } // Sorun: locale bilmez, yuvarlama kaba, "1.234.567" -> "1M" (ondalik kaybi)
YENİ:
NumberFormat nf = NumberFormat.getCompactNumberInstance( Locale.forLanguageTag("tr-TR"), NumberFormat.Style.SHORT); nf.setMaximumFractionDigits(1); nf.format(1_234_567); // -> "1,2 Mn" (Turkce, dile duyarli!)
GERÇEK HAYAT ÖRNEĞİ
- Sosyal medya:
1.234.567takipçi → "1,2 Mn" (Türkçe) veya "1.2M" (İngilizce). - Dosya boyutu:
5.242.880byte → "5.2MB".
CompactNumberFormat.java dosyası SHORT/LONG stillerini ve Türkçe/İngilizce locale'leri yan yana gösterir.
Derleme Notu
Bu özellik Java 12'de kalıcıdır (preview değil); ekstra bayrak gerekmez.
Özellik 3: Teeing Collector
İlgili dosya:
TeeingCollector.java
NEDİR?
Collectors.teeing(downstream1, downstream2, merger): Bir stream'in elemanlarını aynı anda iki ayrı collector'a gönderir, her ikisi de kendi sonucunu üretir, sonra bir merger (BiFunction) bu iki sonucu tek bir sonuca birleştirir. Adı tesisattaki "T-bağlantısı"ndan (tee) gelir: tek akış ikiye ayrılır, işlenir, tekrar birleşir.
NEDEN GELDİ? (Hangi problemi çözüyor)
Bir koleksiyondan iki farklı özet (örn. hem ortalama hem toplam) hesaplamak için önceden ya stream iki kez dolaşılırdı (iki kat iş yükü) ya da karmaşık özel bir collector yazılırdı. teeing bu işi tek geçişte ve okunabilir biçimde çözer.
NE İŞE YARAR?
Tek bir veri geçişiyle iki bağımsız istatistiği hesaplayıp birleştirmenizi sağlar: ortalama + toplam, min + max, geçen sayısı + ortalama, vb.
NEREDE KOLAYLIK SAĞLAR?
Raporlama, analitik, finansal hesaplamalar; özellikle büyük veri setlerinde çift geçişi tek geçişe indirerek performans kazandırır.
ESKİ vs YENİ Kod Karşılaştırması
ESKİ (iki geçiş):
double ortalama = urunler.stream().mapToDouble(Urun::fiyat).average().orElse(0); double toplam = urunler.stream().mapToDouble(Urun::fiyat).sum(); // 2. gecis!
YENİ (tek geçiş, teeing):
var ozet = urunler.stream().collect( Collectors.teeing( Collectors.averagingDouble(Urun::fiyat), // 1. collector Collectors.summingDouble(Urun::fiyat), // 2. collector (ort, top) -> "Ortalama=" + ort + ", Toplam=" + top // merger ) );
GERÇEK HAYAT ÖRNEĞİ
Bir sınıfın not listesinden tek geçişte hem sınıf ortalamasını hem de 50 ve üzeri alan (geçen) öğrenci sayısını hesaplayıp bir rapor nesnesinde birleştirmek. TeeingCollector.java dosyasında ürün fiyatları, öğrenci notları ve min/max fark örnekleri vardır.
Derleme Notu
Bu özellik Java 12'de kalıcıdır; ekstra bayrak gerekmez.
Özellik 4: Shenandoah GC (Deneysel)
Bu özellik için ayrı bir
.javadosyası yoktur; çünkü GC seçimi kodla değil, JVM bayraklarıyla yapılır.
NEDİR?
Shenandoah, Red Hat tarafından geliştirilen düşük duraklama süreli (low-pause-time) bir çöp toplayıcıdır. Java 12'de deneysel (experimental) olarak eklendi.
NEDEN GELDİ? (Hangi problemi çözüyor)
Klasik GC'lerde (Parallel, G1) "stop-the-world" duraklamaları, heap (yığın) büyüdükçe uzar. 100+ GB heap'lerde bu duraklamalar saniyeler sürebilir; düşük gecikme isteyen uygulamalar (oyun sunucuları, finans, gerçek zamanlı sistemler) için kabul edilemez.
NE İŞE YARAR?
Shenandoah, çöp toplama işinin büyük kısmını (özellikle nesnelerin taşınması/evacuation) uygulama thread'leriyle eş zamanlı (concurrent) olarak yapar. Böylece duraklama süresi heap boyutundan büyük ölçüde bağımsız ve çok kısa (genellikle birkaç milisaniye) kalır.
NEREDE KOLAYLIK SAĞLAR?
Büyük heap'li, düşük gecikme kritik uygulamalar.
ZGC ile Karşılaştırma
Java'da iki düşük-gecikme GC vardır: ZGC (Java 11) ve Shenandoah (Java 12). İkisi de eş zamanlı çalışır; Shenandoah daha çok OpenJDK/Red Hat ekosisteminde öne çıkar.
Nasıl Etkinleştirilir? (Java 12'de deneysel olduğu için)
java -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC MyApp
Not: Shenandoah, Java 15'te (JEP 379) production-ready (kalıcı) hale geldi ve artık
-XX:+UseShenandoahGCtek başına yeterlidir.
Avantaj / Dezavantaj
- Avantaj: Çok kısa, öngörülebilir duraklama; heap boyutundan bağımsız gecikme.
- Dezavantaj: Eş zamanlı çalışma CPU ve toplam throughput (iş hacmi) maliyeti getirir; throughput öncelikli batch işler için ideal değildir.
Özellik 5: JVM Constants API
Bu özellik için ayrı
.javadosyası yoktur; çünkü doğrudan uygulama geliştiricileri değil, daha çok derleyici, çerçeve (framework) ve bytecode araçları geliştirenler için bir altyapı API'sidir.
NEDİR?
java.lang.constant paketi (JEP 334) ile gelen, constant pool (sabit havuzu) girdilerini sembolik olarak temsil eden bir API'dir. Başlıca tipler: ConstantDesc, ClassDesc, MethodTypeDesc, MethodHandleDesc, DynamicConstantDesc.
NEDEN GELDİ? (Hangi problemi çözüyor)
JVM'in class dosyalarındaki constant pool, sınıf, metot ve yöntem tipi referanslarını tutar. Bytecode üreten/işleyen araçlar (derleyiciler, ASM benzeri kütüphaneler, dinamik dil çalışma zamanları) bu sabitleri güvenli ve doğrulanabilir biçimde temsil etmek istiyordu. Önceden bunun standart, güvenli bir yolu yoktu; ham Class nesneleri yüklemeyi zorunlu kılıyor, bu da hatalara ve gereksiz sınıf yüklemelerine yol açıyordu.
NE İŞE YARAR?
Bir sabiti (örneğin "java.lang.String sınıfı") gerçekten o sınıfı yüklemeden, salt sembolik (nominal) bir tanımlayıcıyla ifade etmeyi sağlar. Bu, özellikle invokedynamic ve constantdynamic (JEP 309, Java 11) gibi düşük seviye mekanizmalarla çalışan araçlar için kritiktir.
NEREDE KOLAYLIK SAĞLAR?
- Derleyici ve bytecode kütüphaneleri (örn. javac, jlink, dinamik dil run-time'ları).
- Çoğu uygulama geliştiricisi bu API'yi doğrudan kullanmaz; bu daha çok bir "JDK iç altyapısı / araç geliştirici" API'sidir.
Küçük Örnek (kavramsal)
import java.lang.constant.ClassDesc; // "java.lang.String" sinifini YUKLEMEDEN sembolik olarak tanimla: ClassDesc stringDesc = ClassDesc.of("java.lang.String"); System.out.println(stringDesc.descriptorString()); // -> "Ljava/lang/String;"
Preview → Kalıcı Evrimi
Java 12'nin en önemli kavramsal katkılarından biri Preview Feature mekanizmasıdır. Bir özellik önce "preview" olarak yayınlanır, topluluk dener ve geri bildirim verir, gerekirse söz dizimi düzeltilir, sonra "kalıcı (standard)" olur.
Switch Expressions evrimi:
| Java Sürümü | Tarih | Durum | Not |
|---|---|---|---|
| Java 12 | Mart 2019 | Preview (JEP 325) | İlk hali; ->, çoklu case, blok bloklarında break <deger> |
| Java 13 | Eylül 2019 | 2. Preview (JEP 354) | break <deger> yerine yield anahtar sözcüğü getirildi |
| Java 14 | Mart 2020 | KALICI (JEP 361) | Standart hale geldi; artık --enable-preview gerekmez |
Önemli ders: Java 12'de
break <değer>;ile değer döndürülüyordu; Java 13'te bu, daha okunur olanyieldile değiştirildi. Bu, preview mekanizmasının neden değerli olduğunu gösterir: söz dizimi, kalıcı olmadan önce iyileştirilebildi. Bu klasördekiSwitchExpressionsPreview.javadosyası, taşınabilirlik için (Java 14+ ile bayraksız derlensin diye)yieldsöz dizimini kullanır.
Diğer preview özelliklerin de benzer yolu izlediğini unutmayın (örn. Text Blocks: Java 13 preview → Java 15 kalıcı; Records: Java 14 preview → Java 16 kalıcı; Pattern Matching for switch: Java 17 preview → Java 21 kalıcı).
Avantaj / Dezavantaj / Risk Tablosu
Avantajlar
- Switch Expressions: Daha kısa, daha güvenli (fall-through yok), değer döndürebilen, derleyici kapsama kontrolü yapabilen kod.
- Compact Number Formatting: Dile duyarlı, standart, tekrar yazılmayan sayı kısaltma.
- Teeing Collector: Tek geçişte iki istatistik → performans ve okunabilirlik.
- Shenandoah GC: Çok düşük, öngörülebilir GC duraklamaları.
- Daha hızlı başlangıç: Varsayılan CDS arşivi (JEP 341) ile JVM daha hızlı açılır.
Dezavantajlar
- Switch Expressions Java 12'de henüz preview — üretimde kullanmak risklidir (söz dizimi değişebilir, ki gerçekten değişti).
- Shenandoah ve ZGC deneyseldir ve eş zamanlı çalışma throughput maliyeti getirir.
- JVM Constants API sıradan uygulama geliştiricisine doğrudan fayda sağlamaz.
Riskler
- Preview kullanımı:
--enable-previewile derlenen sınıflar yalnızca aynı major sürümün çalışma zamanında çalışır ve sürümler arası taşınamaz. Bu yüzden preview özellikler production'da önerilmez. - Kısa ömür: Java 12 LTS değildir; Java 13 çıkınca desteği bitmiştir. Üretim için Java 17 / Java 21 gibi LTS sürümler tercih edilmelidir. Java 12'nin kalıcı özellikleri zaten bu LTS sürümlerde mevcuttur.
Bu Klasördeki Dosyalar
| Dosya | Açıklama |
|---|---|
README.md | Bu doküman |
SwitchExpressionsPreview.java | Switch Expressions (preview): eski statement vs yeni ->/yield; gün→çalışma saati ve HTTP kodu→mesaj örnekleri |
TeeingCollector.java | Collectors.teeing: ürün fiyatı (ortalama+toplam), öğrenci notu (ortalama+geçen sayısı), min/max fark örnekleri |
CompactNumberFormat.java | getCompactNumberInstance: SHORT/LONG stilleri, Türkçe/İngilizce locale, sosyal medya ve dosya boyutu örnekleri |
Derleme ve Çalıştırma
# Java 14+ (örn. Java 21) ile - hicbir ek bayrak gerekmez: javac SwitchExpressionsPreview.java TeeingCollector.java CompactNumberFormat.java java SwitchExpressionsPreview java TeeingCollector java CompactNumberFormat # Java 12 ile Switch Expressions'i derlemek isterseniz (preview): javac --release 12 --enable-preview SwitchExpressionsPreview.java java --enable-preview SwitchExpressionsPreview
Bu klasördeki tüm
.javadosyaları Java 21 ile derlenip çalıştırılarak doğrulanmıştır.
▶ Kod Örnekleri(3)
CompactNumberFormat
çalıştırılabilir1// =============================================================================
2// CompactNumberFormat.java
3// Java 12 - Compact Number Formatting (JEP 357 / JDK-8188147)
4// =============================================================================
5//
6// NEDIR?
7// ----------------------------------------------------------------------------
8// NumberFormat.getCompactNumberInstance(...) Java 12'de geldi.
9// Buyuk sayilari, insanlarin kolayca okuyabilecegi KISA (kompakt) bicimde
10// gosterir:
11// 1.000 -> "1K" (Ingilizce, SHORT) / "1B" (Turkce, SHORT)
12// 1.000.000 -> "1M" (Ingilizce) / "1Mn" (Turkce)
13// 1.000 -> "1 thousand" (Ingilizce, LONG) / "1 bin" (Turkce, LONG)
14//
15// NEDEN GELDI / HANGI PROBLEMI COZER?
16// ----------------------------------------------------------------------------
17// Onceden sosyal medya beğeni, takipci, goruntuleme sayisi gibi degerleri
18// "1.2K", "3.4M" seklinde gostermek icin EL ile bolme + string birlestirme
19// yapmak gerekiyordu. Bu kod:
20// - locale'e (dile) gore DOGRU ekleri (K/M/B/Bn) bilmez,
21// - cogullasmayi/yuvarlamayi yanlis yapar,
22// - her uygulamada tekrar tekrar yazilir.
23// Compact Number Formatting bu isi locale-aware (dile duyarli) ve standart
24// bicimde halleder.
25//
26// STILLER:
27// - NumberFormat.Style.SHORT : "1K", "1M", "1B"
28// - NumberFormat.Style.LONG : "1 thousand", "1 million", "1 bin"
29//
30// DERLEME / CALISTIRMA (Java 12'de KALICI; preview degil):
31// javac CompactNumberFormat.java
32// java CompactNumberFormat
33// =============================================================================
34
35import java.text.NumberFormat;
36import java.util.Locale;
37
38public class CompactNumberFormat {
39
40 public static void main(String[] args) {
41
42 System.out.println("================================================");
43 System.out.println(" JAVA 12 - COMPACT NUMBER FORMATTING ORNEKLERI");
44 System.out.println("================================================\n");
45
46 long[] sayilar = {123, 1_000, 1_500, 12_345, 1_000_000, 2_300_000, 1_000_000_000L};
47
48 // ---------------------------------------------------------------------
49 // ESKI YONTEM: Manuel bolme + string birlestirme
50 // ---------------------------------------------------------------------
51 // Dezavantajlari:
52 // - Dil/locale farkliliklarini bilmez (hep "K","M" yazar).
53 // - Yuvarlama, ondalik ve cogul kurallari elle yonetilir, hataya acik.
54 // - Her projede yeniden yazilir.
55 System.out.println(">>> ESKI YONTEM (manuel bolme + string birlestirme):");
56 for (long s : sayilar) {
57 System.out.println(" " + s + " -> " + manuelKisalt(s));
58 }
59 System.out.println();
60
61 // ---------------------------------------------------------------------
62 // YENI YONTEM - INGILIZCE (US) locale, SHORT stil
63 // ---------------------------------------------------------------------
64 System.out.println(">>> YENI YONTEM - Ingilizce (US), SHORT stil:");
65 NumberFormat enShort = NumberFormat.getCompactNumberInstance(
66 Locale.US, NumberFormat.Style.SHORT);
67 for (long s : sayilar) {
68 System.out.println(" " + s + " -> " + enShort.format(s));
69 }
70 System.out.println();
71
72 // ---------------------------------------------------------------------
73 // YENI YONTEM - INGILIZCE (US) locale, LONG stil
74 // ---------------------------------------------------------------------
75 System.out.println(">>> YENI YONTEM - Ingilizce (US), LONG stil:");
76 NumberFormat enLong = NumberFormat.getCompactNumberInstance(
77 Locale.US, NumberFormat.Style.LONG);
78 for (long s : sayilar) {
79 System.out.println(" " + s + " -> " + enLong.format(s));
80 }
81 System.out.println();
82
83 // ---------------------------------------------------------------------
84 // YENI YONTEM - TURKCE (tr-TR) locale, SHORT stil
85 // ---------------------------------------------------------------------
86 System.out.println(">>> YENI YONTEM - Turkce (tr-TR), SHORT stil:");
87 Locale tr = Locale.forLanguageTag("tr-TR");
88 NumberFormat trShort = NumberFormat.getCompactNumberInstance(
89 tr, NumberFormat.Style.SHORT);
90 for (long s : sayilar) {
91 System.out.println(" " + s + " -> " + trShort.format(s));
92 }
93 System.out.println();
94
95 // ---------------------------------------------------------------------
96 // YENI YONTEM - TURKCE (tr-TR) locale, LONG stil
97 // ---------------------------------------------------------------------
98 System.out.println(">>> YENI YONTEM - Turkce (tr-TR), LONG stil:");
99 NumberFormat trLong = NumberFormat.getCompactNumberInstance(
100 tr, NumberFormat.Style.LONG);
101 for (long s : sayilar) {
102 System.out.println(" " + s + " -> " + trLong.format(s));
103 }
104 System.out.println();
105
106 // ---------------------------------------------------------------------
107 // ONDALIK HASSASIYET: setMaximumFractionDigits ile "1.5K" gibi gosterim
108 // ---------------------------------------------------------------------
109 // Varsayilan olarak compact format ondalik gostermez (1.500 -> "2K").
110 // Daha hassas gostermek icin maksimum ondalik basamak sayisini artiririz.
111 System.out.println(">>> ONDALIK HASSASIYET (1 ondalik basamak, US/SHORT):");
112 NumberFormat hassas = NumberFormat.getCompactNumberInstance(
113 Locale.US, NumberFormat.Style.SHORT);
114 hassas.setMaximumFractionDigits(1);
115 long[] hassasSayilar = {1_500, 12_345, 2_300_000};
116 for (long s : hassasSayilar) {
117 System.out.println(" " + s + " -> " + hassas.format(s));
118 }
119 System.out.println();
120
121 // ---------------------------------------------------------------------
122 // GERCEK HAYAT ORNEGI 1: Sosyal medya begeni / takipci gosterimi
123 // ---------------------------------------------------------------------
124 System.out.println(">>> GERCEK HAYAT: Sosyal medya istatistikleri (tr-TR):");
125 NumberFormat sosyal = NumberFormat.getCompactNumberInstance(
126 tr, NumberFormat.Style.SHORT);
127 sosyal.setMaximumFractionDigits(1);
128 System.out.println(" Takipci : " + sosyal.format(1_234_567));
129 System.out.println(" Begeni : " + sosyal.format(45_900));
130 System.out.println(" Goruntulenme: " + sosyal.format(12_300_000));
131 System.out.println();
132
133 // ---------------------------------------------------------------------
134 // GERCEK HAYAT ORNEGI 2: Dosya boyutu (byte -> kisa gosterim)
135 // ---------------------------------------------------------------------
136 System.out.println(">>> GERCEK HAYAT: Dosya boyutu gosterimi (US/SHORT):");
137 NumberFormat boyut = NumberFormat.getCompactNumberInstance(
138 Locale.US, NumberFormat.Style.SHORT);
139 boyut.setMaximumFractionDigits(1);
140 long[] boyutlar = {850, 2_048, 5_242_880, 1_073_741_824L};
141 for (long b : boyutlar) {
142 System.out.println(" " + b + " byte -> " + boyut.format(b) + "B");
143 }
144
145 System.out.println("\n================================================");
146 System.out.println(" BITTI.");
147 System.out.println("================================================");
148 }
149
150 // -------------------------------------------------------------------------
151 // ESKI yontemi temsil eden manuel kisaltma metodu (locale'i bilmez!).
152 // -------------------------------------------------------------------------
153 private static String manuelKisalt(long sayi) {
154 if (sayi < 1_000) {
155 return String.valueOf(sayi);
156 } else if (sayi < 1_000_000) {
157 return (sayi / 1_000) + "K";
158 } else if (sayi < 1_000_000_000) {
159 return (sayi / 1_000_000) + "M";
160 } else {
161 return (sayi / 1_000_000_000) + "B";
162 }
163 }
164}SwitchExpressionsPreview
çalıştırılabilir1// =============================================================================
2// SwitchExpressionsPreview.java
3// Java 12 - Switch Expressions (Preview Özelliği - JEP 325)
4// =============================================================================
5//
6// ÖNEMLI NOT (DERLEME / ÇALIŞTIRMA):
7// ----------------------------------------------------------------------------
8// - Switch Expressions, Java 12'de "PREVIEW" (önizleme) olarak geldi.
9// Java 12 ile derlemek için şu komut gerekiyordu:
10// javac --release 12 --enable-preview SwitchExpressionsPreview.java
11// java --enable-preview SwitchExpressionsPreview
12// (--enable-preview olmadan Java 12'de bu söz dizimi DERLENMEZDİ.)
13//
14// - Özellik Java 14'te (JEP 361) KALICI (standard) hale geldi.
15// Java 14 ve sonrasında (örneğin sizin sisteminizdeki Java 21'de)
16// bu dosya HİÇBİR ek bayrağa gerek kalmadan normal şekilde derlenir:
17// javac SwitchExpressionsPreview.java
18// java SwitchExpressionsPreview
19//
20// Bu yüzden aşağıdaki kod, "preview" döneminde yazılmış söz dizimini
21// kullanır; ancak Java 14+ ile --enable-preview olmadan da çalışır.
22// Aşağıdaki yorumlarda hangi parçanın preview'a özgü olduğu açıklanmıştır.
23// =============================================================================
24
25public class SwitchExpressionsPreview {
26
27 public static void main(String[] args) {
28
29 System.out.println("================================================");
30 System.out.println(" JAVA 12 - SWITCH EXPRESSIONS (PREVIEW) ORNEKLERI");
31 System.out.println("================================================\n");
32
33 // ---------------------------------------------------------------------
34 // BÖLÜM 1: ESKİ YÖNTEM (Klasik switch STATEMENT)
35 // ---------------------------------------------------------------------
36 // Java 12 öncesinde switch bir "ifade (expression)" değil, bir
37 // "deyim (statement)" idi. Yani doğrudan bir DEĞER ÜRETEMEZDİ;
38 // değeri ancak yan etki (bir değişkene atama) ile elde edebilirdik.
39 //
40 // PROBLEMLER:
41 // 1) Her case sonunda 'break' yazmayı UNUTURSAK "fall-through"
42 // (bir alttaki case'e düşme) hatası oluşur. Sessiz bir bug'tır.
43 // 2) Değer üretmek için ekstra bir değişken tanımlamak gerekir.
44 // 3) Çok satırlı, gürültülü ve hataya açık koddur.
45 System.out.println(">>> ESKI YONTEM (klasik switch statement):");
46 for (int gun = 1; gun <= 7; gun++) {
47 int calismaSaatiEski;
48 switch (gun) {
49 case 1: // Pazartesi
50 case 2: // Sali
51 case 3: // Carsamba
52 case 4: // Persembe
53 case 5: // Cuma
54 calismaSaatiEski = 8; // hafta ici tam mesai
55 break; // <-- break unutulursa fall-through!
56 case 6: // Cumartesi
57 calismaSaatiEski = 4; // yarim gun
58 break;
59 case 7: // Pazar
60 calismaSaatiEski = 0; // tatil
61 break;
62 default:
63 calismaSaatiEski = -1; // gecersiz gun
64 }
65 System.out.println(" Gun " + gun + " -> " + calismaSaatiEski + " saat");
66 }
67 System.out.println();
68
69 // ---------------------------------------------------------------------
70 // BÖLÜM 2: YENİ YÖNTEM (Switch EXPRESSION + '->' oku)
71 // ---------------------------------------------------------------------
72 // Java 12'de gelen yeni '->' (ok) söz dizimi:
73 // - Ok'un sağındaki ifade ÇALIŞIR ve DEĞER ÜRETİR.
74 // - 'break' YOKTUR; otomatik olarak fall-through OLMAZ. Güvenli!
75 // - Birden çok etiketi tek case'te virgülle yazabiliriz:
76 // case 1, 2, 3, 4, 5 ->
77 // - switch'in tamamı bir DEĞER döndürür; doğrudan atayabiliriz.
78 System.out.println(">>> YENI YONTEM (switch expression, '->' oku):");
79 for (int gun = 1; gun <= 7; gun++) {
80 int calismaSaatiYeni = switch (gun) {
81 // Cogu etiketi tek satirda birlestirebiliyoruz (coklu case):
82 case 1, 2, 3, 4, 5 -> 8; // hafta ici
83 case 6 -> 4; // cumartesi
84 case 7 -> 0; // pazar
85 default -> -1; // gecersiz
86 }; // <-- DİKKAT: expression olduğu için sonunda ';' var.
87 System.out.println(" Gun " + gun + " -> " + calismaSaatiYeni + " saat");
88 }
89 System.out.println();
90
91 // ---------------------------------------------------------------------
92 // BÖLÜM 3: 'yield' İLE ÇOK SATIRLI CASE BLOĞU
93 // ---------------------------------------------------------------------
94 // Bir case'in sağında tek bir ifade değil de birkaç satır işlem
95 // yapmamız gerekiyorsa { } blok açarız ve değeri 'yield' ile döndürürüz.
96 // ('yield', switch expression'dan değer döndürmenin yoludur;
97 // metottan değer döndüren 'return' ile karıştırılmamalıdır.)
98 System.out.println(">>> 'yield' ile cok satirli case blogu:");
99 for (int gun = 1; gun <= 7; gun++) {
100 String aciklama = switch (gun) {
101 case 1, 2, 3, 4, 5 -> {
102 int saat = 8;
103 // ... burada loglama, hesaplama vs. yapilabilir ...
104 yield "Hafta ici - " + saat + " saat mesai"; // <-- yield
105 }
106 case 6 -> {
107 yield "Cumartesi - yarim gun (4 saat)";
108 }
109 case 7 -> "Pazar - tatil"; // tek ifade -> yield gerekmez
110 default -> "Gecersiz gun!";
111 };
112 System.out.println(" Gun " + gun + " -> " + aciklama);
113 }
114 System.out.println();
115
116 // ---------------------------------------------------------------------
117 // BÖLÜM 4: GERÇEK HAYAT ÖRNEĞİ - HTTP DURUM KODU -> MESAJ
118 // ---------------------------------------------------------------------
119 System.out.println(">>> GERCEK HAYAT: HTTP durum kodu -> kullanici mesaji:");
120 int[] kodlar = {200, 201, 301, 404, 500, 418, 999};
121 for (int kod : kodlar) {
122 String mesaj = httpDurumMesaji(kod);
123 System.out.println(" HTTP " + kod + " -> " + mesaj);
124 }
125 System.out.println();
126
127 // ---------------------------------------------------------------------
128 // BÖLÜM 5: ESKİ '\' (iki nokta) söz dizimini de switch EXPRESSION
129 // olarak kullanabilirsiniz (eski stil ':' + yield).
130 // ---------------------------------------------------------------------
131 // Not: Java 12 ':' ile de expression yazmaya izin verir; ancak bu
132 // durumda fall-through riski geri gelir. '->' kullanmak tercih edilir.
133 System.out.println(">>> Eski ':' stiliyle expression (yield ile):");
134 int puan = 85;
135 String harfNotu = switch (puan / 10) {
136 case 10, 9 : yield "AA";
137 case 8 : yield "BA";
138 case 7 : yield "BB";
139 case 6 : yield "CC";
140 default : yield "FF (kaldi)";
141 };
142 System.out.println(" Puan " + puan + " -> Harf notu: " + harfNotu);
143
144 System.out.println("\n================================================");
145 System.out.println(" BITTI.");
146 System.out.println("================================================");
147 }
148
149 // -------------------------------------------------------------------------
150 // Yardımcı metot: HTTP durum kodunu '->' switch expression ile mesaja çevirir.
151 // -------------------------------------------------------------------------
152 private static String httpDurumMesaji(int kod) {
153 return switch (kod) {
154 case 200, 201, 204 -> "Basarili";
155 case 301, 302 -> "Yonlendirme";
156 case 400 -> "Hatali istek";
157 case 401, 403 -> "Yetkisiz erisim";
158 case 404 -> "Bulunamadi";
159 case 500, 502, 503 -> "Sunucu hatasi";
160 default -> "Bilinmeyen durum kodu (" + kod + ")";
161 };
162 }
163}TeeingCollector
çalıştırılabilir1// =============================================================================
2// TeeingCollector.java
3// Java 12 - Teeing Collector (Collectors.teeing) - JDK-8209685
4// =============================================================================
5//
6// NEDIR?
7// ----------------------------------------------------------------------------
8// Collectors.teeing(downstream1, downstream2, merger):
9// Bir stream'in elemanlarini AYNI ANDA iki ayri collector'a (downstream)
10// gonderir; her iki collector da kendi sonucunu uretir; en sonda
11// 'merger' (birlestirici BiFunction) bu iki sonucu TEK bir sonuca birlestirir.
12//
13// Adi "tee" (T borusu) tesisatcilikteki T-baglantisindan gelir: tek bir akis
14// ikiye ayrilir, iki farkli isleme tabi tutulur, sonra tekrar birlestirilir.
15//
16// NEDEN GELDI / HANGI PROBLEMI COZER?
17// ----------------------------------------------------------------------------
18// Java 12 oncesinde bir koleksiyondan IKI farkli ozet (orn. hem ortalama
19// hem toplam, hem min hem max) hesaplamak istediginizde ya:
20// (a) stream'i IKI KEZ dolasmaniz (iki ayri stream() cagrisi),
21// (b) ya da ozel/karmasik bir collector yazmaniz gerekiyordu.
22// teeing ile TEK GECISTE iki sonucu birlikte hesaplayip birlestirebiliriz.
23//
24// DERLEME / CALISTIRMA:
25// Collectors.teeing Java 12'de KALICI (standard) olarak geldi (preview degil).
26// javac TeeingCollector.java
27// java TeeingCollector
28// =============================================================================
29
30import java.util.List;
31import java.util.stream.Collectors;
32
33public class TeeingCollector {
34
35 // Basit bir "Urun" kaydi (ad + fiyat).
36 record Urun(String ad, double fiyat) {}
37
38 // teeing'in merger'inin urettigi sonucu tutacak kayit.
39 record FiyatOzeti(double ortalama, long adet, double toplam) {}
40
41 public static void main(String[] args) {
42
43 System.out.println("================================================");
44 System.out.println(" JAVA 12 - TEEING COLLECTOR ORNEKLERI");
45 System.out.println("================================================\n");
46
47 List<Urun> urunler = List.of(
48 new Urun("Klavye", 450.0),
49 new Urun("Mouse", 250.0),
50 new Urun("Monitor", 3200.0),
51 new Urun("Kulaklik", 800.0),
52 new Urun("Webcam", 600.0)
53 );
54
55 // ---------------------------------------------------------------------
56 // ESKI YONTEM: Stream'i IKI KEZ dolasarak ortalama ve toplam hesaplama
57 // ---------------------------------------------------------------------
58 // Dezavantaj: ayni veri seti uzerinde iki ayri stream gecisi yapilir.
59 // Buyuk veri setlerinde bu, iki katlik is yuku demektir.
60 System.out.println(">>> ESKI YONTEM (iki ayri stream gecisi):");
61 double ortalamaEski = urunler.stream()
62 .mapToDouble(Urun::fiyat)
63 .average()
64 .orElse(0.0);
65 double toplamEski = urunler.stream()
66 .mapToDouble(Urun::fiyat)
67 .sum();
68 System.out.printf(" Ortalama fiyat: %.2f TL%n", ortalamaEski);
69 System.out.printf(" Toplam fiyat : %.2f TL%n", toplamEski);
70 System.out.println();
71
72 // ---------------------------------------------------------------------
73 // YENI YONTEM: Collectors.teeing ile TEK GECISTE iki sonuc + birlestirme
74 // ---------------------------------------------------------------------
75 // 1. downstream -> ortalama (Collectors.averagingDouble)
76 // 2. downstream -> adet (Collectors.counting)
77 // merger -> iki sonucu FiyatOzeti'ne birlestirir; ayrica
78 // ortalama * adet ile toplami da hesaplayip ekleriz.
79 System.out.println(">>> YENI YONTEM (Collectors.teeing - tek gecis):");
80 FiyatOzeti ozet = urunler.stream().collect(
81 Collectors.teeing(
82 Collectors.averagingDouble(Urun::fiyat), // 1. collector
83 Collectors.counting(), // 2. collector
84 (ort, adet) -> new FiyatOzeti(ort, adet, ort * adet) // merger
85 )
86 );
87 System.out.printf(" Ortalama fiyat: %.2f TL%n", ozet.ortalama());
88 System.out.printf(" Urun adedi : %d%n", ozet.adet());
89 System.out.printf(" Toplam fiyat : %.2f TL%n", ozet.toplam());
90 System.out.println();
91
92 // ---------------------------------------------------------------------
93 // GERCEK HAYAT ORNEGI: Ogrenci notlari -> ortalama + gecen ogrenci sayisi
94 // ---------------------------------------------------------------------
95 // Tek geciste hem sinif ortalamasini hem de 50 ve uzeri alan
96 // (gecen) ogrenci sayisini birlikte hesapliyoruz.
97 System.out.println(">>> GERCEK HAYAT: Sinif notlari analizi:");
98 List<Integer> notlar = List.of(45, 80, 55, 30, 90, 65, 48, 72, 100, 50);
99
100 record SinifRaporu(double ortalama, long gecenSayisi, int toplamOgrenci) {}
101
102 SinifRaporu rapor = notlar.stream().collect(
103 Collectors.teeing(
104 // 1. downstream: tum notlarin ortalamasi
105 Collectors.averagingInt(Integer::intValue),
106 // 2. downstream: 50 ve uzeri alanlari say (gecenler)
107 Collectors.filtering(n -> n >= 50, Collectors.counting()),
108 // merger: iki sonucu birlestir, toplam ogrenciyi de ekle
109 (ort, gecen) -> new SinifRaporu(ort, gecen, notlar.size())
110 )
111 );
112 System.out.printf(" Sinif ortalamasi : %.1f%n", rapor.ortalama());
113 System.out.printf(" Gecen ogrenci : %d / %d%n",
114 rapor.gecenSayisi(), rapor.toplamOgrenci());
115 System.out.printf(" Basari orani : %%%.0f%n",
116 100.0 * rapor.gecenSayisi() / rapor.toplamOgrenci());
117 System.out.println();
118
119 // ---------------------------------------------------------------------
120 // EK ORNEK: teeing ile MIN ve MAX'i tek geciste bulup fark hesaplama
121 // ---------------------------------------------------------------------
122 System.out.println(">>> EK ORNEK: En ucuz / en pahali urun farki:");
123 record MinMax(double min, double max, double fark) {}
124
125 MinMax minMax = urunler.stream().collect(
126 Collectors.teeing(
127 Collectors.minBy((a, b) -> Double.compare(a.fiyat(), b.fiyat())),
128 Collectors.maxBy((a, b) -> Double.compare(a.fiyat(), b.fiyat())),
129 (minOpt, maxOpt) -> {
130 double min = minOpt.map(Urun::fiyat).orElse(0.0);
131 double max = maxOpt.map(Urun::fiyat).orElse(0.0);
132 return new MinMax(min, max, max - min);
133 }
134 )
135 );
136 System.out.printf(" En ucuz : %.2f TL%n", minMax.min());
137 System.out.printf(" En pahali: %.2f TL%n", minMax.max());
138 System.out.printf(" Fark : %.2f TL%n", minMax.fark());
139
140 System.out.println("\n================================================");
141 System.out.println(" BITTI.");
142 System.out.println("================================================");
143 }
144}