Java 9 (Eylül 2017) — Detaylı Türkçe Analiz
| Bilgi | Değer | |-------|-------| | Sürüm | Java SE 9 (JDK 9) | | Çıkış Tarihi | 21 Eylül 2017 | | LTS mi? | HAYIR (LTS değildir) | | Destek Durumu | SONA ERDİ — Java 9 kısa ömürlü bir "feature release" idi. Genel d…
Java 9 (Eylül 2017) — Detaylı Türkçe Analiz
Sürüm Bilgileri
| Bilgi | Değer |
|---|---|
| Sürüm | Java SE 9 (JDK 9) |
| Çıkış Tarihi | 21 Eylül 2017 |
| LTS mi? | HAYIR (LTS değildir) |
| Destek Durumu | SONA ERDİ — Java 9 kısa ömürlü bir "feature release" idi. Genel destek Mart 2018'de Java 10 çıkınca bitti. Üretim ortamlarında kullanılmamalıdır. |
| Bir Sonraki LTS | Java 11 (Eylül 2018) |
| Kod Adı / En Önemli Proje | Project Jigsaw (Modül Sistemi / JPMS) |
NOT: Java 9, Java tarihindeki en büyük mimari değişikliklerden birini getirdi: Modül Sistemi (JPMS). Bu yüzden "küçük" bir sürüm olmasına rağmen, geçiş açısından en riskli sürümlerden biridir. Java 8'den Java 9'a geçiş, basit bir JDK güncellemesi değil; çoğu zaman bir uyumluluk projesi olmuştur.
İçindekiler ve İlgili Dosyalar
| Özellik | Dosya |
|---|---|
| Modül Sistemi (JPMS / Project Jigsaw) | ModulSistemiOrnek.java |
Collection Factory metotları (List.of, Set.of, Map.of) | CollectionFactoryOrnek.java |
Stream geliştirmeleri (takeWhile, dropWhile, ofNullable, iterate) | StreamGelistirmeleri.java |
Optional geliştirmeleri (ifPresentOrElse, or, stream) | OptionalGelistirmeleri.java |
| Private interface metotları | PrivateInterfaceMetot.java |
| JShell (REPL) | JShellNotlari.md |
1) Modül Sistemi (JPMS — Java Platform Module System / Project Jigsaw)
Detaylı kod ve
module-info.javaörneği için:ModulSistemiOrnek.java
NEDİR?
Java 9'a kadar kodu organize etmenin en üst birimi JAR dosyasıydı. JAR'lar aslında sadece sıkıştırılmış .class dosyalarıydı; içlerinde "ben hangi paketleri dışarıya açıyorum, hangi başka kütüphanelere bağımlıyım" bilgisi yoktu. Modül sistemi, paketlerin üzerine yeni bir katman ekler: modül. Bir modül, module-info.java adlı özel bir dosya ile kendini tanımlar:
- Hangi paketleri dışarıya açtığını (
exports), - Hangi modüllere bağımlı olduğunu (
requires), - Hangi servisleri kullandığını/sağladığını (
uses/provides).
NEDEN GELDİ? (Hangi problem?)
- JAR Hell (JAR Cehennemi): Classpath üzerinde aynı sınıfın iki farklı sürümü bulunabiliyor, hangisinin yükleneceği belirsizdi. Eksik bir bağımlılık ancak çalışma anında
NoClassDefFoundErrorile fark ediliyordu. - Güçlü kapsülleme (encapsulation) eksikliği:
publicolan her şey classpath'teki herkese açıktı.sun.misc.Unsafe,com.sun.*gibi dahili (internal) API'ler herkes tarafından kullanılıyor, JDK ekibi de bunları değiştiremiyordu. - Devasa monolitik JRE:
rt.jartek parça, ~60 MB civarında bir dosyaydı. Küçük bir uygulama için bile tüm JDK gerekiyordu. IoT / küçük cihazlar için bu fazlaydı.
NE İŞE YARAR?
- Güvenilir konfigürasyon (reliable configuration): Eksik modül başlangıçta tespit edilir; çalışma anında patlamaz.
- Güçlü kapsülleme: Sadece
exportsile açılan paketler erişilebilir.publicolsa bile dışarı açılmamış paket görünmez. - Ölçeklenebilir platform: JDK kendisi de ~95 modüle bölündü (
java.base,java.sql,java.xml...).jlinkaracı ile sadece ihtiyaç duyulan modülleri içeren küçük, özel bir runtime üretilebilir.
NEREDE KOLAYLIK SAĞLAR?
- Büyük, çok katmanlı kurumsal uygulamalarda mimari sınırların derleyici tarafından zorlanması.
- Mikroservis / container imajlarının küçültülmesi (
jlinkile 30-40 MB'lık runtime). - Kütüphane geliştiricilerinin "iç" paketlerini gizleyip yalnızca API'yi açabilmesi.
ESKİ vs YENİ
ESKİ (Java 8 — classpath):
javac -cp lib/*.jar src/... java -cp app.jar:lib/*.jar com.example.Main # Tüm public sınıflar herkese açık. Eksik JAR ancak runtime'da patlar.
YENİ (Java 9 — modulepath):
// module-info.java module com.banka.cekirdek { requires java.sql; // bağımlılık açıkça belirtilir exports com.banka.cekirdek.api; // sadece bu paket dışarı açık // com.banka.cekirdek.internal -> hiç exports edilmedi => GİZLİ }
javac -d out --module-source-path src $(find src -name "*.java") java --module-path out -m com.banka.cekirdek/com.banka.cekirdek.Main
GERÇEK HAYAT ÖRNEĞİ
Bir bankacılık uygulamasında internal paketinde hassas hesaplama mantığı var. Java 8'de bu paket public sınıflar içerdiği için başka takımlar (hatta dışarıdan kütüphaneler) doğrudan ona erişip kendi mantıklarını gömebiliyordu. JPMS ile internal paketi exports edilmediğinden, derleyici bu erişimi derleme anında reddeder. Mimari karar, dokümantasyon ricası olmaktan çıkıp derleyici garantisine dönüşür.
2) Collection Factory Metotları
NEDİR?
List.of(...), Set.of(...), Map.of(...), Map.ofEntries(...) — küçük, değiştirilemez (immutable) koleksiyonları tek satırda oluşturan statik fabrika metotları.
NEDEN GELDİ?
Java 8'de sabit bir liste oluşturmak külfetliydi ve sonuçların çoğu değiştirilebilir kalıyordu (hata kaynağı). "Double-brace initialization" gibi kötü idiomlar gizli iç sınıf ve bellek sızıntısı üretiyordu.
NE İŞE YARAR / NEREDE KOLAYLIK?
Test verisi, sabit konfigürasyon, lookup tabloları gibi yerlerde kısa ve güvenli (değiştirilemez) koleksiyon üretir.
ESKİ vs YENİ
// ESKİ List<String> l = Collections.unmodifiableList(Arrays.asList("a","b","c")); Map<String,Integer> m = new HashMap<>(); m.put("a",1); m.put("b",2); // YENİ List<String> l = List.of("a","b","c"); Map<String,Integer> m = Map.of("a",1,"b",2);
GERÇEK HAYAT ÖRNEĞİ
Bir HTTP cevabında dönecek sabit hata kodları tablosu. Map.of(...) ile tek satırda, yanlışlıkla değiştirilemeyecek şekilde tanımlanır.
DİKKAT: Bu koleksiyonlar
nulleleman kabul etmez (NullPointerException),Set.of/Map.oftekrar eden anahtar/eleman kabul etmez (IllegalArgumentException) ve hepsi immutable'dır (add/put->UnsupportedOperationException).
3) Stream API Geliştirmeleri
NEDİR?
takeWhile(predicate)— koşul doğru olduğu sürece baştan eleman alır, ilk yanlışta durur.dropWhile(predicate)— koşul doğru olduğu sürece baştan eleman atar, ilk yanlıştan itibaren kalanı alır.Stream.ofNullable(t)—tnull ise boş stream, değilse tek elemanlı stream döner.Stream.iterate(seed, hasNext, next)— sonlu (predicate'li) iterate. Java 8'deki sonsuziteratee güvenli,fordöngüsüne benzer bir alternatif.
NEDEN GELDİ?
filter koşulu tüm elemanlara uygular; "sıralı veride bir eşiğe kadar al/atla" senaryosunu ifade edemiyordu. Java 8'de iterate sonsuzdu, limit ile kesmek gerekiyordu.
ESKİ vs YENİ
// ESKİ: sıralı veride eşiğe kadar al list.stream().filter(x -> x < 100) // YANLIŞ: 100'den sonra gelen küçükleri de alır // YENİ list.stream().takeWhile(x -> x < 100) // doğru: ilk >=100'de durur
GERÇEK HAYAT ÖRNEĞİ
Tarihe göre sıralı log satırlarını okurken belirli bir saatten sonrasını atlamak (takeWhile) ya da bir başlık bloğunu geçip gövdeye ulaşmak (dropWhile).
4) Optional Geliştirmeleri
NEDİR?
ifPresentOrElse(action, emptyAction)— değer varsa bir şey yap, yoksa başka bir şey yap.or(supplier)— boşsa başka bir Optional ile fallback (yeniOptionaldöner).stream()—Optional'ı 0 veya 1 elemanlı birStream'e çevirir;flatMapile boş olanları eler.
NEDEN GELDİ?
Java 8'de ifPresent vardı ama "yoksa şunu yap" için çirkin if (opt.isPresent()) ... else ... yazmak gerekiyordu. or ve stream ile zincirleme/fonksiyonel akış tamamlandı.
ESKİ vs YENİ
// ESKİ if (opt.isPresent()) log(opt.get()); else logEksik(); // YENİ opt.ifPresentOrElse(this::log, this::logEksik);
GERÇEK HAYAT ÖRNEĞİ
Önce önbellekten (cache), yoksa veritabanından kullanıcıyı bul: cache.find(id).or(() -> db.find(id)).
5) Private Interface Metotları
NEDİR?
Interface içinde private ve private static metot tanımlanabilmesi. Bu metotlar dışarı görünmez; yalnızca aynı interface'in default/static metotları tarafından kullanılır.
NEDEN GELDİ?
Java 8 default metotları getirdi ama iki default metot ortak mantığı paylaşmak istediğinde, ortak kodu ya kopyalamak ya da istemeden public default olarak dışarı açmak zorundaydık. Bu, kapsüllemeyi bozuyordu.
ESKİ vs YENİ
// ESKİ: ortak kodu public default olarak açmak zorunda kalmak (sızıntı) default void log1(){ /* ortak kod kopya */ } default void log2(){ /* ortak kod kopya */ } // YENİ private void ortakLog(String s){ /* ortak kod tek yerde */ } default void log1(){ ortakLog("1"); } default void log2(){ ortakLog("2"); }
GERÇEK HAYAT ÖRNEĞİ
Bir Repository interface'inde birden çok default metot ortak doğrulama/loglama yapar; bu mantık private bir yardımcı metotta toplanır, API kirlenmez.
Kısaca Diğer Java 9 Özellikleri
Try-with-resources Geliştirmesi
Java 7'de try-with-resources içinde kaynak için yeni bir değişken bildirmek zorunluydu. Java 9'da zaten effectively final olan mevcut bir değişken doğrudan kullanılabilir:
// ESKİ (Java 7/8) try (Reader r2 = r) { ... } // gereksiz ikinci değişken // YENİ (Java 9) final Reader r = ...; try (r) { ... } // doğrudan
Process API Geliştirmeleri (ProcessHandle)
İşletim sistemi süreçleriyle çalışmak için yeni java.lang.ProcessHandle API'si. Süreç PID'sini, sahibini, başlangıç zamanını, alt süreçlerini öğrenme; onExit() ile sürecin bitişini CompletableFuture olarak bekleme.
ProcessHandle.current().pid(); // kendi PID'imiz ProcessHandle.allProcesses().count(); // sistemdeki süreç sayısı
HTTP/2 Client (incubator)
jdk.incubator.http altında modern, HTTP/2 ve WebSocket destekli, asenkron bir HTTP istemcisi. Java 9'da incubator (deneysel) statüsündeydi, paket adı incubator idi. Java 11'de standartlaşıp java.net.http.HttpClient oldu. Amaç: eski, kullanışsız HttpURLConnection'ı emekliye ayırmak.
Multi-Release JAR (MRJAR)
Tek bir JAR içinde farklı Java sürümleri için farklı .class dosyaları barındırma. META-INF/versions/9/ altına Java 9'a özel sınıflar konur; eski JVM kök dizindeki sınıfları, Java 9+ JVM ise versiyonlu olanı kullanır. Kütüphane yazarları için: tek JAR ile hem eski hem yeni JVM'i en iyi şekilde destekleme.
Java 8'den Java 9'a GEÇİŞTE NE DEĞİŞTİ?
- Modül sistemi geldi. Mevcut classpath uygulamaları "unnamed module" olarak çalışmaya devam eder; yani hemen modüle dönmek zorunlu değildir. Ama JDK'nın kendisi modülerleşti.
- Dahili API'ler kapatıldı.
sun.misc.Unsafeve benzericom.sun.*/sun.*paketleri artık varsayılan olarak erişilemez. Bunları kullanan eski kütüphaneler derleme/çalışma anında uyarı veya hata üretir. -ile başlayan birçok kaldırılmış API:jdk.internal.*gizlendi.- Sürüm dizgisi değişti:
1.9değil, artık9.System.getProperty("java.version")->9. Sürüm string'ini parse eden eski kodlar kırılabilir. rt.jarvetools.jarkaldırıldı. Bu dosyalara doğrudan referans veren build script'leri bozulur.Class.forName/ classloader hiyerarşisi değişti (bootstrap classloader artıknullyerine yeni bir yapı).- JShell (REPL) geldi — bkz.
JShellNotlari.md. - Underscore (
_) artık tek başına geçerli bir tanımlayıcı değil (ileride keyword olacağı için ayrıldı).
Avantajlar / Dezavantajlar / Riskler
Avantajlar
- Güçlü kapsülleme: mimari sınırlar derleyici tarafından zorlanır.
- Güvenilir konfigürasyon: eksik bağımlılık başlangıçta yakalanır (runtime sürprizi yok).
jlinkile küçük, özel runtime imajları (container/IoT için ideal).- Daha temiz Stream/Optional/Collection API'leri sayesinde daha az boilerplate.
- JShell ile hızlı prototipleme ve öğrenme.
Dezavantajlar
- Öğrenme eğrisi:
module-info.java,requires/exports/openskavramları yeni ve karmaşık. - Yansıma (reflection) tabanlı framework'ler (Spring, Hibernate, Jackson)
opensdirektifi gerektirebilir; yoksaInaccessibleObjectException. - Build araçları (Maven/Gradle) ve IDE'lerin tam modül desteğine kavuşması zaman aldı.
Riskler (Geçişte en sık karşılaşılanlar)
- Internal API erişiminin kapanması: Eski kütüphaneler
sun.misc.Unsafekullanıyorsa kırılır. (Geçici çözüm:--add-exports,--add-opensJVM bayrakları.) - Split package sorunu: Aynı paketin iki ayrı JAR/modülde bulunması modül sisteminde yasaktır; eski projelerde sık görülür ve build'i bozar.
- Reflection / setAccessible kırılmaları: Güçlü kapsülleme yüzünden
field.setAccessible(true)artık her yere işlemez;opensgerekir. - Sürüm parse eden kod:
"1.8"formatı bekleyen string parse mantıkları"9"ile patlar. - Kaldırılan modüller/araçlar:
rt.jar,tools.jar, JAXB/JAX-WS gibi Java EE modülleri Java 9'dadeprecated(ve sonra kaldırıldı) —--add-modules java.se.eegibi çözümler gerekti.
SONUÇ: Java 9 LTS olmadığından doğrudan üretim hedefi değildi; çoğu kurum onun getirdiği değişiklikleri Java 11 LTS'e geçerken sindirdi. Yine de Java 9, modern Java'nın (modüller, jlink, yeni API'ler) temellerini attığı için tarihsel olarak çok önemlidir.
▶ Kod Örnekleri(5)
CollectionFactoryOrnek
çalıştırılabilir1/*
2 * =============================================================================
3 * JAVA 9 - COLLECTION FACTORY METOTLARI
4 * List.of / Set.of / Map.of / Map.ofEntries
5 * =============================================================================
6 *
7 * NEDİR? Küçük, DEĞİŞTİRİLEMEZ (immutable) koleksiyonları tek satırda
8 * oluşturan statik fabrika metotları.
9 *
10 * NEDEN? Java 8'de sabit koleksiyon yaratmak hem uzun hem de sonuç çoğu zaman
11 * DEĞİŞTİRİLEBİLİR kalıyordu (hata kaynağı). "Double-brace" idiomu ise
12 * gizli iç sınıf üretip bellek sızıntısına yol açıyordu.
13 *
14 * Derleme/Çalıştırma:
15 * javac --release 9 CollectionFactoryOrnek.java
16 * java CollectionFactoryOrnek
17 * =============================================================================
18 */
19
20import java.util.ArrayList;
21import java.util.Arrays;
22import java.util.Collections;
23import java.util.HashMap;
24import java.util.List;
25import java.util.Map;
26import java.util.Set;
27
28public class CollectionFactoryOrnek {
29
30 public static void main(String[] args) {
31
32 // =====================================================================
33 // 1) LISTE OLUŞTURMA - ESKİ vs YENİ
34 // =====================================================================
35 System.out.println("--- 1) List olusturma ---");
36
37 // ESKİ YÖNTEM 1: Arrays.asList -> SABİT BOYUT ama eleman set edilebilir,
38 // ayrıca add/remove UnsupportedOperationException atar (yarı mutable).
39 List<String> eskiAsList = Arrays.asList("elma", "armut", "kiraz");
40
41 // ESKİ YÖNTEM 2: Gerçekten immutable istiyorsak sarmalamak gerekiyordu:
42 List<String> eskiImmutable =
43 Collections.unmodifiableList(new ArrayList<>(Arrays.asList("elma", "armut")));
44
45 // YENİ YÖNTEM (Java 9): tek satır, tam immutable:
46 List<String> yeni = List.of("elma", "armut", "kiraz");
47
48 System.out.println("Eski (asList) : " + eskiAsList);
49 System.out.println("Eski (unmodifiable): " + eskiImmutable);
50 System.out.println("Yeni (List.of) : " + yeni);
51
52 // =====================================================================
53 // 2) IMMUTABLE DAVRANIŞI - değiştirmeye çalışınca ne olur?
54 // =====================================================================
55 System.out.println("\n--- 2) Immutable davranisi ---");
56 try {
57 yeni.add("muz"); // UnsupportedOperationException bekleniyor
58 } catch (UnsupportedOperationException e) {
59 System.out.println("List.of() degistirilemez -> add() denemesi: "
60 + e.getClass().getSimpleName());
61 }
62
63 // =====================================================================
64 // 3) NULL KABUL ETMEME
65 // =====================================================================
66 System.out.println("\n--- 3) null kabul etmeme ---");
67 // ESKİ: Arrays.asList(null) sorunsuz null eleman alabilir (gizli hata kaynağı).
68 List<String> nullIcerenEski = Arrays.asList("a", null, "c");
69 System.out.println("Eski asList null kabul etti: " + nullIcerenEski);
70
71 // YENİ: List.of null elemanı REDDEDER.
72 try {
73 List<String> patlar = List.of("a", null, "c");
74 System.out.println(patlar); // buraya gelmez
75 } catch (NullPointerException e) {
76 System.out.println("List.of() null reddetti -> NullPointerException");
77 }
78
79 // =====================================================================
80 // 4) SET.of - tekrar eden eleman REDDEDİLİR
81 // =====================================================================
82 System.out.println("\n--- 4) Set.of ---");
83 Set<Integer> kume = Set.of(1, 2, 3, 4);
84 System.out.println("Set.of(1,2,3,4) = " + kume);
85 try {
86 Set<Integer> hata = Set.of(1, 2, 2); // tekrar eden eleman!
87 System.out.println(hata);
88 } catch (IllegalArgumentException e) {
89 System.out.println("Set.of() tekrar eden eleman reddetti -> IllegalArgumentException");
90 }
91
92 // =====================================================================
93 // 5) MAP.of ve MAP.ofEntries - ESKİ vs YENİ
94 // =====================================================================
95 System.out.println("\n--- 5) Map olusturma ---");
96
97 // ESKİ YÖNTEM: tek tek put
98 Map<String, Integer> eskiMap = new HashMap<>();
99 eskiMap.put("bir", 1);
100 eskiMap.put("iki", 2);
101 eskiMap.put("uc", 3);
102
103 // ESKİ "double-brace" idiomu (KÖTÜ pratik - anonim iç sınıf + bellek sızıntısı):
104 @SuppressWarnings("serial")
105 Map<String, Integer> doubleBrace = new HashMap<String, Integer>() {{
106 put("bir", 1);
107 put("iki", 2);
108 }};
109
110 // YENİ: Map.of (en fazla 10 anahtar-değer çifti destekler)
111 Map<String, Integer> yeniMap = Map.of("bir", 1, "iki", 2, "uc", 3);
112
113 // YENİ: Map.ofEntries -> 10'dan fazla giriş veya daha okunaklı yapı için
114 Map<String, Integer> ofEntries = Map.ofEntries(
115 Map.entry("bir", 1),
116 Map.entry("iki", 2),
117 Map.entry("uc", 3),
118 Map.entry("dort", 4)
119 );
120
121 System.out.println("Eski (put) : " + eskiMap);
122 System.out.println("Eski (doubleBrace): " + doubleBrace);
123 System.out.println("Yeni (Map.of) : " + yeniMap);
124 System.out.println("Yeni (ofEntries) : " + ofEntries);
125
126 // Map.of de immutable ve null reddeder:
127 try {
128 yeniMap.put("dort", 4);
129 } catch (UnsupportedOperationException e) {
130 System.out.println("Map.of() degistirilemez -> put() : "
131 + e.getClass().getSimpleName());
132 }
133
134 // =====================================================================
135 // 6) GERÇEK HAYAT ÖRNEĞİ: Sabit HTTP hata kodu tablosu
136 // =====================================================================
137 System.out.println("\n--- 6) Gercek hayat: sabit lookup tablosu ---");
138 Map<Integer, String> httpKodlari = Map.of(
139 200, "OK",
140 404, "Bulunamadi",
141 500, "Sunucu Hatasi"
142 );
143 int gelenKod = 404;
144 System.out.println("HTTP " + gelenKod + " => "
145 + httpKodlari.getOrDefault(gelenKod, "Bilinmeyen"));
146 }
147}ModulSistemiOrnek
çalıştırılabilir1/*
2 * =============================================================================
3 * JAVA 9 - MODÜL SİSTEMİ (JPMS / Project Jigsaw)
4 * =============================================================================
5 *
6 * Bu dosya, Java 9'un EN ÖNEMLİ özelliği olan Modül Sistemini DERİNLEMESİNE
7 * anlatır. Modül sistemi normalde birden çok klasör + module-info.java
8 * dosyası gerektirir; bu yüzden gerçek modül yapısını YORUM BLOKLARI olarak
9 * veriyoruz. Aşağıdaki "main" metodu ise modül sisteminin RUNTIME tarafını
10 * (ModuleLayer, Module API, ServiceLoader) çalıştırılabilir biçimde gösterir.
11 *
12 * NOT: Bu tek dosya, "unnamed module" (isimsiz modül) içinde de derlenip
13 * çalışabilir; çünkü gösterdiğimiz API'ler java.base içindedir.
14 *
15 * Derleme/Çalıştırma (tek dosya, classpath):
16 * javac --release 9 ModulSistemiOrnek.java
17 * java ModulSistemiOrnek
18 * =============================================================================
19 */
20
21import java.lang.module.ModuleDescriptor; // Modül tanımını okumak için (Java 9+)
22import java.util.ServiceLoader; // uses/provides ile çalışan servis mekanizması
23
24public class ModulSistemiOrnek {
25
26 /*
27 * -------------------------------------------------------------------------
28 * BÖLÜM 1: MODÜL NEDİR? (Kavramsal)
29 * -------------------------------------------------------------------------
30 * Java 9'a kadar kodun en üst organizasyon birimi PAKET ve JAR idi.
31 * JAR'lar sadece sıkıştırılmış .class dosyalarıydı; "ben kime bağımlıyım,
32 * hangi paketi dışarı açıyorum" bilgisini TAŞIMIYORDU.
33 *
34 * Modül = isimlendirilmiş bir paket grubu + kendini tanımlayan
35 * "module-info.java" dosyası.
36 *
37 * Bir modül şunları açıkça beyan eder:
38 * - requires : hangi modüllere bağımlıyım
39 * - exports : hangi paketlerimi dışarıya açıyorum (geri kalanı GİZLİ)
40 * - opens : hangi paketlerimi REFLECTION'a açıyorum (Spring/Jackson vs.)
41 * - uses : hangi servis arayüzünü kullanacağım (ServiceLoader)
42 * - provides : bu servis arayüzü için hangi implementasyonu sağlıyorum
43 */
44
45 /*
46 * -------------------------------------------------------------------------
47 * BÖLÜM 2: ÖRNEK MODÜLER UYGULAMA YAPISI (Dosya yerleşimi)
48 * -------------------------------------------------------------------------
49 *
50 * Bir bankacılık uygulamasını 3 modüle bölelim:
51 *
52 * src/
53 * ├─ com.banka.cekirdek/ <-- ÇEKİRDEK modül (API + iç mantık)
54 * │ ├─ module-info.java
55 * │ └─ com/banka/cekirdek/
56 * │ ├─ api/HesapServisi.java (DIŞARI AÇIK paket)
57 * │ ├─ api/Hesap.java (DIŞARI AÇIK paket)
58 * │ └─ internal/HesapHesaplayici.java (GİZLİ paket - exports yok!)
59 * │
60 * ├─ com.banka.log/ <-- SERVİS SAĞLAYICI modül
61 * │ ├─ module-info.java
62 * │ └─ com/banka/log/DosyaLogcu.java (LogServisi implementasyonu)
63 * │
64 * └─ com.banka.uygulama/ <-- ANA uygulama modülü
65 * ├─ module-info.java
66 * └─ com/banka/uygulama/Main.java
67 */
68
69 /*
70 * -------------------------------------------------------------------------
71 * BÖLÜM 3: module-info.java ÖRNEKLERİ
72 * -------------------------------------------------------------------------
73 *
74 * ====== src/com.banka.cekirdek/module-info.java ======
75 *
76 * module com.banka.cekirdek {
77 *
78 * // Bu modül JDBC kullanıyor; java.sql modülüne bağımlı.
79 * requires java.sql;
80 *
81 * // 'api' paketi DIŞARIYA AÇIK. Başka modüller kullanabilir.
82 * exports com.banka.cekirdek.api;
83 *
84 * // DİKKAT: 'internal' paketi EXPORTS EDİLMEDİ.
85 * // Public sınıflar bile içerse, dışarıdan ERİŞİLEMEZ.
86 * // Derleyici, başka modülün buna erişimini REDDEDER. (Güçlü kapsülleme)
87 *
88 * // Bir servis arayüzü tanımlayıp dışa açıyoruz:
89 * exports com.banka.cekirdek.spi; // LogServisi arayüzü burada
90 *
91 * // Bu modül 'LogServisi' implementasyonlarını ServiceLoader ile arar:
92 * uses com.banka.cekirdek.spi.LogServisi;
93 * }
94 *
95 * ====== src/com.banka.log/module-info.java ======
96 *
97 * module com.banka.log {
98 * requires com.banka.cekirdek; // arayüze ulaşmak için
99 *
100 * // LogServisi arayüzünün implementasyonunu SAĞLIYORUZ:
101 * provides com.banka.cekirdek.spi.LogServisi
102 * with com.banka.log.DosyaLogcu;
103 * }
104 *
105 * ====== src/com.banka.uygulama/module-info.java ======
106 *
107 * module com.banka.uygulama {
108 * requires com.banka.cekirdek;
109 *
110 * // Spring/Jackson gibi bir framework bu paketi reflection ile okusun
111 * // istiyorsak (yoksa InaccessibleObjectException alırız):
112 * opens com.banka.uygulama to com.fasterxml.jackson.databind;
113 * }
114 *
115 * -------------------------------------------------------------------------
116 * DERLEME / ÇALIŞTIRMA (çok modüllü):
117 *
118 * javac -d out --module-source-path src $(find src -name "*.java")
119 * java --module-path out -m com.banka.uygulama/com.banka.uygulama.Main
120 *
121 * jlink ile özel KÜÇÜK runtime üretmek:
122 * jlink --module-path "$JAVA_HOME/jmods:out" \
123 * --add-modules com.banka.uygulama \
124 * --output ozel-runtime
125 * ./ozel-runtime/bin/java -m com.banka.uygulama/com.banka.uygulama.Main
126 * -------------------------------------------------------------------------
127 */
128
129 /*
130 * -------------------------------------------------------------------------
131 * BÖLÜM 4: ESKİ (Java 8 classpath) vs YENİ (Java 9 module)
132 * -------------------------------------------------------------------------
133 *
134 * ESKİ (Java 8):
135 * - Tüm public sınıflar classpath'teki herkese AÇIK.
136 * - 'internal' diye işaretlemek sadece bir İSİMLENDİRME KONVANSİYONU,
137 * derleyici garantisi YOK.
138 * - Eksik JAR -> RUNTIME'da NoClassDefFoundError.
139 * - sun.misc.Unsafe gibi iç API'ler serbestçe kullanılır.
140 *
141 * YENİ (Java 9):
142 * - Sadece 'exports' edilen paketler erişilebilir.
143 * - Eksik 'requires' -> DERLEME/BAŞLANGIÇ anında hata (güvenilir konfig.).
144 * - JDK iç API'leri kapalı; gerekirse --add-exports/--add-opens.
145 * -------------------------------------------------------------------------
146 */
147
148 public static void main(String[] args) {
149 System.out.println("=== JAVA 9 MODÜL SİSTEMİ - RUNTIME TARAFI ===\n");
150
151 // ---------------------------------------------------------------------
152 // 1) Çalışan kodun bulunduğu MODÜLÜ öğrenme.
153 // Bu sınıf classpath'ten çalışıyorsa "unnamed module" içindedir.
154 // ---------------------------------------------------------------------
155 Module buModul = ModulSistemiOrnek.class.getModule();
156 System.out.println("Bu sinifin modulu isimli mi? : " + buModul.isNamed());
157 System.out.println("Modul adi (isimsizse null/bos): " + buModul.getName());
158 System.out.println();
159
160 // ---------------------------------------------------------------------
161 // 2) JDK'nın kendisi de modülerdir. 'String' sınıfı 'java.base'
162 // modülündedir. Bunu runtime'da kanıtlayalım.
163 // ---------------------------------------------------------------------
164 Module stringModulu = String.class.getModule();
165 System.out.println("java.lang.String hangi modulde? : " + stringModulu.getName());
166
167 Module listModulu = java.util.List.class.getModule();
168 System.out.println("java.util.List hangi modulde? : " + listModulu.getName());
169
170 Module sqlModulu = java.sql.Connection.class.getModule();
171 System.out.println("java.sql.Connection hangi modulde?: " + sqlModulu.getName());
172 System.out.println();
173
174 // ---------------------------------------------------------------------
175 // 3) Bir modülün TANIMINI (descriptor) okuma.
176 // module-info'daki requires/exports bilgisi runtime'da burada durur.
177 // ---------------------------------------------------------------------
178 ModuleDescriptor tanim = stringModulu.getDescriptor();
179 if (tanim != null) {
180 System.out.println("java.base modulunun tanimi:");
181 System.out.println(" Ad : " + tanim.name());
182 System.out.println(" Otomatik mi? : " + tanim.isAutomatic());
183 System.out.println(" Disa acilan paket sayisi (exports): " + tanim.exports().size());
184 // İlk birkaç export edilen paketi gösterelim:
185 tanim.exports().stream()
186 .map(ModuleDescriptor.Exports::source)
187 .sorted()
188 .limit(5)
189 .forEach(p -> System.out.println(" exports -> " + p));
190 }
191 System.out.println();
192
193 // ---------------------------------------------------------------------
194 // 4) Sistemde yüklü bazı modülleri listeleme (ModuleLayer.boot()).
195 // Java 9'da çalışan tüm modüller "boot layer" içinde bulunur.
196 // ---------------------------------------------------------------------
197 System.out.println("Boot layer'daki bazi moduller (ilk 8):");
198 ModuleLayer.boot().modules().stream()
199 .map(Module::getName)
200 .sorted()
201 .limit(8)
202 .forEach(ad -> System.out.println(" - " + ad));
203 System.out.println();
204
205 // ---------------------------------------------------------------------
206 // 5) uses / provides -> ServiceLoader mantığı.
207 // Modüler dünyada 'uses com.banka.cekirdek.spi.LogServisi' diyen modül,
208 // implementasyonu ServiceLoader ile şöyle bulur (sözde kod):
209 //
210 // ServiceLoader<LogServisi> sl = ServiceLoader.load(LogServisi.class);
211 // LogServisi log = sl.findFirst().orElseThrow();
212 //
213 // Burada gerçek bir JDK servisini (zaten yüklü) örnekleyelim:
214 // ---------------------------------------------------------------------
215 System.out.println("ServiceLoader ornegi (JDK'nin kendi servisleri):");
216 ServiceLoader<java.nio.file.spi.FileSystemProvider> saglayicilar =
217 ServiceLoader.load(java.nio.file.spi.FileSystemProvider.class);
218 long adet = 0;
219 for (java.nio.file.spi.FileSystemProvider p : saglayicilar) {
220 System.out.println(" Bulunan FileSystemProvider: " + p.getScheme());
221 adet++;
222 if (adet >= 3) break;
223 }
224 if (adet == 0) {
225 System.out.println(" (Bu ortamda ek saglayici bulunamadi - normaldir.)");
226 }
227
228 System.out.println("\nOzet: Modul sistemi = guclu kapsulleme + guvenilir konfigurasyon");
229 System.out.println(" + olceklenebilir platform (jlink). Java 9'un kalbidir.");
230 }
231}OptionalGelistirmeleri
çalıştırılabilir1/*
2 * =============================================================================
3 * JAVA 9 - OPTIONAL GELİŞTİRMELERİ
4 * ifPresentOrElse / or / stream
5 * =============================================================================
6 *
7 * Derleme/Çalıştırma:
8 * javac --release 9 OptionalGelistirmeleri.java
9 * java OptionalGelistirmeleri
10 * =============================================================================
11 */
12
13import java.util.List;
14import java.util.Optional;
15import java.util.stream.Collectors;
16
17public class OptionalGelistirmeleri {
18
19 public static void main(String[] args) {
20
21 // =====================================================================
22 // 1) ifPresentOrElse : varsa şunu yap, YOKSA şunu yap.
23 // =====================================================================
24 System.out.println("--- 1) ifPresentOrElse ---");
25 Optional<String> dolu = Optional.of("Ahmet");
26 Optional<String> bos = Optional.empty();
27
28 // ESKİ (Java 8): çirkin if/else, çünkü ifPresent'in "else"i yoktu.
29 if (dolu.isPresent()) {
30 System.out.println("Eski: kullanici = " + dolu.get());
31 } else {
32 System.out.println("Eski: kullanici yok");
33 }
34
35 // YENİ (Java 9): tek ifade, hem varlık hem yokluk eylemi.
36 dolu.ifPresentOrElse(
37 ad -> System.out.println("Yeni: kullanici = " + ad),
38 () -> System.out.println("Yeni: kullanici yok")
39 );
40 bos.ifPresentOrElse(
41 ad -> System.out.println("Yeni: kullanici = " + ad),
42 () -> System.out.println("Yeni: kullanici yok (bos optional)")
43 );
44
45 // =====================================================================
46 // 2) or : boşsa BAŞKA BİR OPTIONAL ile fallback (yeni Optional döner).
47 // =====================================================================
48 System.out.println("\n--- 2) or ---");
49
50 // GERÇEK HAYAT: önce cache, yoksa veritabanı, yoksa varsayılan.
51 System.out.println("Sonuc: " + kullaniciBul("42").orElse("BULUNAMADI"));
52 System.out.println("Sonuc: " + kullaniciBul("999").orElse("BULUNAMADI"));
53
54 // orElse vs or farkı:
55 // orElse(T) -> doğrudan DEĞER döner
56 // or(Supplier<Optional>) -> başka bir OPTIONAL döner, zincirlenebilir
57 Optional<String> zincir = bos
58 .or(() -> Optional.empty()) // hala boş
59 .or(() -> Optional.of("varsayilan")); // burada dolar
60 System.out.println("or zinciri sonucu: " + zincir.get());
61
62 // =====================================================================
63 // 3) stream : Optional'ı 0 veya 1 elemanlı Stream'e çevirir.
64 // flatMap ile boş olanları eler -> Optional listesini temizlemenin
65 // en şık yolu.
66 // =====================================================================
67 System.out.println("\n--- 3) Optional.stream ---");
68
69 List<Optional<String>> optionalListesi = List.of(
70 Optional.of("a"),
71 Optional.empty(),
72 Optional.of("b"),
73 Optional.empty(),
74 Optional.of("c")
75 );
76
77 // ESKİ (Java 8): filter(isPresent) + map(get) gerekirdi.
78 List<String> eski = optionalListesi.stream()
79 .filter(Optional::isPresent)
80 .map(Optional::get)
81 .collect(Collectors.toList());
82 System.out.println("Eski (filter+map): " + eski);
83
84 // YENİ (Java 9): tek flatMap, hem temizler hem açar.
85 List<String> yeni = optionalListesi.stream()
86 .flatMap(Optional::stream)
87 .collect(Collectors.toList());
88 System.out.println("Yeni (flatMap stream): " + yeni);
89 }
90
91 // Cache'i simüle eden basit metot.
92 private static Optional<String> cachedenBul(String id) {
93 if ("42".equals(id)) return Optional.of("Cache: Mehmet");
94 return Optional.empty();
95 }
96
97 // Veritabanını simüle eden metot.
98 private static Optional<String> veritabanindanBul(String id) {
99 if ("100".equals(id)) return Optional.of("DB: Ayse");
100 return Optional.empty();
101 }
102
103 // Java 9 'or' ile temiz fallback zinciri.
104 private static Optional<String> kullaniciBul(String id) {
105 return cachedenBul(id)
106 .or(() -> veritabanindanBul(id));
107 }
108}PrivateInterfaceMetot
çalıştırılabilir1/*
2 * =============================================================================
3 * JAVA 9 - PRIVATE INTERFACE METOTLARI
4 * (private ve private static)
5 * =============================================================================
6 *
7 * NEDİR? Interface içinde 'private' ve 'private static' metot tanımlamak.
8 * Bu metotlar dışarıdan GÖRÜNMEZ; sadece aynı interface'in
9 * default/static metotları tarafından kullanılır.
10 *
11 * NEDEN? Java 8 default metotları getirdi. Ama iki default metot ortak mantık
12 * paylaşmak isteyince ya kodu KOPYALAMAK ya da ortak kodu 'public default'
13 * yapıp istemeden API'ye SIZDIRMAK gerekiyordu. private metotlar bunu çözer.
14 *
15 * Derleme/Çalıştırma:
16 * javac --release 9 PrivateInterfaceMetot.java
17 * java PrivateInterfaceMetot
18 * =============================================================================
19 */
20
21import java.time.LocalDateTime;
22import java.util.List;
23
24public class PrivateInterfaceMetot {
25
26 // =========================================================================
27 // GERÇEK HAYAT: Bir "Logger" interface'i. Birden çok default metot ortak
28 // formatlama/zaman damgası mantığını paylaşıyor. Bu ortak mantık private
29 // metotlara konularak API kirletilmiyor.
30 // =========================================================================
31 interface Logger {
32
33 // --- DIŞA AÇIK (public) default metotlar ---
34 default void bilgi(String mesaj) {
35 // Ortak mantığı private metottan çağırıyoruz:
36 yaz(seviyeEkle("BILGI", mesaj));
37 }
38
39 default void uyari(String mesaj) {
40 yaz(seviyeEkle("UYARI", mesaj));
41 }
42
43 default void hata(String mesaj) {
44 yaz(seviyeEkle("HATA", mesaj));
45 }
46
47 // --- PRIVATE (örnek) metot: 3 default metodun ORTAK formatlaması ---
48 // Dışarıdan çağrılamaz; sadece interface içinde kullanılır.
49 private String seviyeEkle(String seviye, String mesaj) {
50 return zamanDamgasi() + " [" + seviye + "] " + mesaj;
51 }
52
53 // --- PRIVATE STATIC metot: durum gerektirmeyen ortak yardımcı ---
54 private static String zamanDamgasi() {
55 return LocalDateTime.now().toString();
56 }
57
58 // Bu, implementasyona bırakılan TEK soyut metot (gerçek çıktı yeri).
59 void yaz(String satir);
60 }
61
62 // =========================================================================
63 // Interface'i uygulayan somut sınıf. Sadece 'yaz' metodunu doldurur.
64 // bilgi/uyari/hata zaten default; ortak mantık private metotlarda.
65 // =========================================================================
66 static class KonsolLogger implements Logger {
67 @Override
68 public void yaz(String satir) {
69 System.out.println(satir);
70 }
71 }
72
73 // =========================================================================
74 // ESKİ (Java 8) YAKLAŞIMI - kıyas için (yorum içinde):
75 //
76 // interface EskiLogger {
77 // // Ortak kodu private yapamadığımız için ya kopyalıyorduk:
78 // default void bilgi(String m) {
79 // yaz(LocalDateTime.now() + " [BILGI] " + m); // kopya format mantığı
80 // }
81 // default void uyari(String m) {
82 // yaz(LocalDateTime.now() + " [UYARI] " + m); // yine kopya
83 // }
84 // // ...ya da ortak metodu 'public default' yapıp API'yi kirletiyorduk:
85 // default String seviyeEkle(String s, String m) { ... } // İSTEMEDEN public!
86 // }
87 // =========================================================================
88
89 public static void main(String[] args) {
90 System.out.println("=== Private Interface Metotlari ===\n");
91
92 Logger log = new KonsolLogger();
93 log.bilgi("Uygulama basladi");
94 log.uyari("Disk doluluk orani %85");
95 log.hata("Veritabani baglantisi koptu");
96
97 System.out.println("\nNot: 'seviyeEkle' ve 'zamanDamgasi' metotlari private oldugu");
98 System.out.println("icin disaridan (log.seviyeEkle(...)) cagrilamaz -> derleme hatasi olurdu.");
99
100 // İspat: KonsolLogger nesnesinin dışarıya açık tek ekstra davranışı
101 // bilgi/uyari/hata; private metotlar arayüzde gizli.
102 List<String> disaAcikDavranislar = List.of("bilgi", "uyari", "hata", "yaz");
103 System.out.println("Disa acik davranislar: " + disaAcikDavranislar);
104 }
105}StreamGelistirmeleri
çalıştırılabilir1/*
2 * =============================================================================
3 * JAVA 9 - STREAM API GELİŞTİRMELERİ
4 * takeWhile / dropWhile / Stream.ofNullable / Stream.iterate(seed,hasNext,next)
5 * =============================================================================
6 *
7 * Derleme/Çalıştırma:
8 * javac --release 9 StreamGelistirmeleri.java
9 * java StreamGelistirmeleri
10 * =============================================================================
11 */
12
13import java.util.Arrays;
14import java.util.List;
15import java.util.stream.Collectors;
16import java.util.stream.Stream;
17
18public class StreamGelistirmeleri {
19
20 public static void main(String[] args) {
21
22 // =====================================================================
23 // 1) takeWhile : koşul DOĞRU olduğu sürece baştan al, ilk YANLIŞta dur.
24 // =====================================================================
25 System.out.println("--- 1) takeWhile ---");
26 // SIRALI bir liste düşünelim (örn. artan ölçüm değerleri).
27 List<Integer> olcumler = List.of(2, 4, 6, 8, 5, 10, 1);
28
29 // ESKİ YANLIŞ DENEME: filter tüm elemanlara uygulanır, "ilk eşikte dur" demez.
30 List<Integer> eskiFilter = olcumler.stream()
31 .filter(x -> x < 8)
32 .collect(Collectors.toList());
33 System.out.println("Eski filter(x<8) : " + eskiFilter
34 + " <- 5 ve 1 de geldi (istemiyorduk!)");
35
36 // YENİ takeWhile: ilk 8 görünce DURUR.
37 List<Integer> yeniTake = olcumler.stream()
38 .takeWhile(x -> x < 8)
39 .collect(Collectors.toList());
40 System.out.println("Yeni takeWhile(x<8): " + yeniTake + " <- 8'de durdu");
41
42 // =====================================================================
43 // 2) dropWhile : koşul DOĞRU olduğu sürece baştan AT, ilk YANLIŞtan
44 // itibaren KALANI al.
45 // =====================================================================
46 System.out.println("\n--- 2) dropWhile ---");
47 List<Integer> yeniDrop = olcumler.stream()
48 .dropWhile(x -> x < 8)
49 .collect(Collectors.toList());
50 System.out.println("dropWhile(x<8) : " + yeniDrop + " <- ilk 8'den itibaren kalanlar");
51
52 // GERÇEK HAYAT: bir metin dosyasının başlık satırlarını atlayıp gövdeye geçmek.
53 List<String> dosya = List.of(
54 "# baslik",
55 "# yazar: ahmet",
56 "# tarih: 2017",
57 "veri-satiri-1",
58 "veri-satiri-2",
59 "# bu yorum govdede" // dropWhile bunu ATMAZ; ilk yanlistan sonrasi alinir
60 );
61 List<String> govde = dosya.stream()
62 .dropWhile(s -> s.startsWith("#"))
63 .collect(Collectors.toList());
64 System.out.println("Basliklar atlandi: " + govde);
65
66 // =====================================================================
67 // 3) Stream.ofNullable : null ise BOŞ stream, değilse tek elemanlı stream.
68 // =====================================================================
69 System.out.println("\n--- 3) Stream.ofNullable ---");
70 String varOlan = "merhaba";
71 String yokOlan = null;
72
73 // ESKİ: null kontrolünü elle yapmak gerekirdi.
74 long eskiSayim = (yokOlan == null) ? 0 : 1;
75 System.out.println("Eski elle null kontrolu: " + eskiSayim);
76
77 // YENİ:
78 System.out.println("ofNullable(varOlan).count() = "
79 + Stream.ofNullable(varOlan).count()); // 1
80 System.out.println("ofNullable(null).count() = "
81 + Stream.ofNullable(yokOlan).count()); // 0
82
83 // GERÇEK HAYAT: bir map'ten gelebilecek null'ı stream akışında temiz işlemek.
84 List<String> sehirler = Arrays.asList("Istanbul", null, "Ankara", null, "Izmir");
85 List<String> temiz = sehirler.stream()
86 .flatMap(Stream::ofNullable) // null'lar otomatik elenir
87 .collect(Collectors.toList());
88 System.out.println("null'lar elendi: " + temiz);
89
90 // =====================================================================
91 // 4) Stream.iterate(seed, hasNext, next) : SONLU iterate (for döngüsü gibi).
92 // =====================================================================
93 System.out.println("\n--- 4) Stream.iterate (3 argumanli, sonlu) ---");
94
95 // ESKİ (Java 8): iterate SONSUZdu, limit ile kesmek gerekirdi.
96 List<Integer> eskiIterate = Stream.iterate(1, n -> n * 2)
97 .limit(5)
98 .collect(Collectors.toList());
99 System.out.println("Eski iterate+limit: " + eskiIterate);
100
101 // YENİ (Java 9): koşul predicate'i ile, tıpkı 'for' gibi.
102 // for(int i=1; i<=100; i*=2) gibi:
103 List<Integer> yeniIterate = Stream.iterate(1, n -> n <= 100, n -> n * 2)
104 .collect(Collectors.toList());
105 System.out.println("Yeni iterate(seed,hasNext,next): " + yeniIterate);
106
107 // GERÇEK HAYAT: sayfalama. 1. sayfadan başla, boş gelene kadar (burada <=50) ilerle.
108 System.out.println("\n--- Gercek hayat: sayfalama simulasyonu ---");
109 Stream.iterate(1, sayfa -> sayfa <= 50, sayfa -> sayfa + 10)
110 .forEach(sayfa -> System.out.println(" Sayfa offset getiriliyor: " + sayfa));
111 }
112}