Java 8 — Detaylı Sürüm Analizi ve Örnekler
> Bu klasör, Java 8 sürümünün getirdiği tüm önemli özellikleri derinlemesine > anlatan Türkçe bir dokümantasyon ve her özellik için çalışan, derlenebilir > örnek .java dosyaları içerir.
Java 8 — Detaylı Sürüm Analizi ve Örnekler
Bu klasör, Java 8 sürümünün getirdiği tüm önemli özellikleri derinlemesine anlatan Türkçe bir dokümantasyon ve her özellik için çalışan, derlenebilir örnek
.javadosyaları içerir.
İçindekiler
- Sürüm Bilgisi
- Java 8 Neden Devrim Niteliğindedir?
- Özellikler
- 1. Lambda İfadeleri
- 2. Fonksiyonel Arayüzler
- 3. Method References
- 4. Stream API
- 5. Optional Sınıfı
- 6. Default ve Static Metotlar
- 7. Yeni Date/Time API (java.time)
- 8. Nashorn JavaScript Engine
- 9. Collectors ve Gruplama
- 10. CompletableFuture (Asenkron)
- 11. StringJoiner ve String.join
- 12. Repeatable & Type Annotations
- 13. Arrays.parallelSort ve PermGen→Metaspace
- Java 8'e Geçiş: Avantajlar, Dezavantajlar, Riskler
- Dosya Listesi ve Çalıştırma
Sürüm Bilgisi
| Bilgi | Değer |
|---|---|
| Sürüm | Java SE 8 (JDK 1.8) |
| Çıkış Tarihi | 18 Mart 2014 |
| LTS Durumu | Evet — Uzun Vadeli Destek (LTS). Java'nın en uzun ömürlü, en yaygın kullanılan sürümlerinden biridir. |
| Önemli Sürümler | Oracle JDK ve OpenJDK olarak dağıtıldı. Oracle kamu güncellemelerini 2019'da sonlandırdı (ticari destek devam etti). OpenJDK tabanlı dağıtımlar (Adoptium/Temurin, Amazon Corretto, Azul Zulu, Red Hat) destek vermeye devam ediyor. |
| JLS / JVM | Java Language Specification 8, ayrıca PermGen kaldırılıp Metaspace getirildi. |
Oracle / OpenJDK Notu
Java 8 döneminde Oracle JDK ile OpenJDK arasında pratikte çok az fark vardı. 2019 sonrası Oracle, ticari kullanımda lisans (abonelik) modeline geçti; bu yüzden bugün çoğu kurum OpenJDK tabanlı ücretsiz dağıtımlar (Eclipse Temurin, Amazon Corretto vb.) kullanır. Java 8, hâlâ kurumsal dünyada en çok production'da çalışan sürümlerden biridir.
Java 8 Neden Devrim Niteliğindedir?
Java 8, dilin tarihindeki en büyük paradigma değişimini getirdi: fonksiyonel programlama unsurlarını ana akım Java'ya soktu.
Java 8 öncesinde Java tamamen nesne yönelimli (OOP) ve emir kipi (imperative) bir dildi: "bilgisayara adım adım NASIL yapacağını söyle". Java 8 ile birlikte deklaratif (bildirimsel) programlama mümkün oldu: "NE istediğini söyle, nasıl yapılacağıyla kütüphane ilgilensin".
Bu değişimi mümkün kılan üç temel taş:
- Lambda ifadeleri — davranışı (kod) bir veri gibi geçirebilmek.
- Fonksiyonel arayüzler — lambdaların "tipi".
- Stream API — koleksiyonlar üzerinde fonksiyonel boru hatları.
Bunların yanında Optional (null güvenliği), java.time (modern tarih), default metotlar (arayüz evrimi) ve CompletableFuture (asenkron) gibi yenilikler, Java'yı modern bir dil seviyesine taşıdı. İşte bu yüzden Java 8, "öncesi ve sonrası" diye anılan bir dönüm noktasıdır.
Özellikler
Her özellik için: NEDİR / NEDEN GELDİ / NE İŞE YARAR / NEREDE KOLAYLIK /
ESKİ vs YENİ / GERÇEK HAYAT başlıklarını bulacaksınız ve ilgili .java
dosyasına referans verilmiştir.
1. Lambda İfadeleri
Bkz: LambdaOrnekleri.java
- NEDİR? İsimsiz (anonim) bir fonksiyondur.
(parametreler) -> { gövde }sözdizimiyle, bir davranışı (kod parçasını) doğrudan değer gibi geçirmemizi sağlar. - NEDEN GELDİ? Java 8 öncesinde bir davranış geçirmek için anonim iç sınıf yazmak zorundaydık. 1 satırlık iş için 5-6 satırlık "tören kodu" (boilerplate) gerekiyordu.
- NE İŞE YARAR / NEREDE KOLAYLIK? Sıralama (Comparator), olay dinleyicileri, Stream işlemleri, callback'ler. Kodu kısaltır ve okunabilir kılar.
ESKİ YÖNTEM (anonim iç sınıf):
Collections.sort(isimler, new Comparator<String>() { @Override public int compare(String a, String b) { return a.compareTo(b); } });
YENİ YÖNTEM (lambda):
Collections.sort(isimler, (a, b) -> a.compareTo(b));
- GERÇEK HAYAT: Bir e-ticaret sitesinde çalışan listesini önce departmana,
sonra isme göre sıralamak; bir kullanıcı listesini
forEachile dolaşmak.
2. Fonksiyonel Arayüzler
Bkz: FonksiyonelArayuzler.java
- NEDİR? İçinde tek bir soyut metot bulunan arayüz (SAM — Single
Abstract Method). Lambdaların ve method reference'ların "tipi" budur.
@FunctionalInterfaceanotasyonu, ikinci soyut metot eklenirse derleme hatası vererek güvence sağlar. - NEDEN GELDİ? Lambdaların atanabileceği bir tip gerekiyordu. Java 8,
java.util.functionpaketinde hazır, genel amaçlı arayüzler getirdi; böylece her ihtiyaç için yeni arayüz tanımlamaya gerek kalmadı. - NE İŞE YARAR: Davranışı parametre olarak geçirmenin standart yolunu sunar.
En çok kullanılanlar:
| Arayüz | Girdi → Çıktı | Metot | Örnek kullanım |
|---|---|---|---|
Function<T,R> | T → R | apply | Dönüştürme (map) |
Consumer<T> | T → void | accept | Yan etki (yazdırma) |
Supplier<T> | () → T | get | Tembel (lazy) üretim |
Predicate<T> | T → boolean | test | Filtreleme koşulu |
BiFunction<T,U,R> | (T,U) → R | apply | İki girdili işlem |
UnaryOperator<T> | T → T | apply | Aynı tipe dönüştürme |
BinaryOperator<T> | (T,T) → T | apply | İki aynı tipi birleştirme |
- GERÇEK HAYAT: E-ticarette
Predicate<Urun> stoktavePredicate<Urun> pahalikurallarını.and()ile birleştirip "stokta VE pahalı" ürünleri filtrelemek;Function<Urun, Double>ile KDV'li fiyat hesaplamak.
3. Method References
Bkz: MethodReferences.java
- NEDİR? Lambda'nın daha da kısa hâli. Eğer bir lambda yalnızca var olan
bir metodu çağırıyorsa,
::operatörüyle doğrudan metodu işaret ederiz. - NEDEN GELDİ?
x -> Sinif.metot(x)gibi sadece delege eden lambdalar hâlâ gürültülüydü. Method reference niyeti netleştirir ve okunabilirliği artırır.
Dört türü:
| Tür | Söz dizimi | Lambda karşılığı |
|---|---|---|
| 1. Static metot | Integer::parseInt | s -> Integer.parseInt(s) |
| 2. Belirli nesnenin metodu | System.out::println | s -> System.out.println(s) |
| 3. Rastgele nesnenin örnek metodu | String::toUpperCase | s -> s.toUpperCase() |
| 4. Constructor referansı | Kullanici::new | ad -> new Kullanici(ad) |
ESKİ vs YENİ:
// LAMBDA list.stream().map(s -> s.toUpperCase()); // METHOD REFERENCE list.stream().map(String::toUpperCase);
- GERÇEK HAYAT: Çalışanları maaşa göre sıralarken
Comparator.comparing(Calisan::getMaas); isim listesini toplu olarak nesneye çevirmek için.map(Kullanici::new).
4. Stream API
Bkz: StreamApiOrnekleri.java
- NEDİR? Koleksiyonlar üzerinde deklaratif işlem yapmayı sağlayan bir
veri akışı (pipeline) API'si:
kaynak → ara işlemler → sonlandırıcı. - NEDEN GELDİ? Elle yazılan iç içe
fordöngüleri ve geçici listeler, filtrele-dönüştür-topla gibi işlemleri okunması zor ve hataya açık hâle getiriyordu. Stream bunları tek bir akıcı zincire indirger. - NE İŞE YARAR:
filter,map,reduce,collect,flatMap,sorted,limit,distinct, istatistik, ve paralel stream ile çoklu çekirdek.
Önemli kavramlar:
- Lazy (tembel): Ara işlemler, terminal işlem çağrılana kadar çalışmaz.
- Tek kullanımlık: Bir stream tüketildikten sonra tekrar kullanılamaz.
- Paralel:
.parallelStream()veya.parallel()ile çekirdeklere dağılır.
ESKİ YÖNTEM:
List<String> sonuc = new ArrayList<>(); for (Urun u : urunler) { if (u.getKategori().equals("Elektronik") && u.getFiyat() > 1000) { sonuc.add(u.getAd().toUpperCase()); } }
YENİ YÖNTEM (Stream):
List<String> sonuc = urunler.stream() .filter(u -> u.getKategori().equals("Elektronik")) .filter(u -> u.getFiyat() > 1000) .map(u -> u.getAd().toUpperCase()) .collect(Collectors.toList());
- GERÇEK HAYAT: E-ticarette "en pahalı 3 ürünü bul", "tüm siparişlerin
kalemlerini
flatMapile düzleştir", "toplam stok değerinireduceile hesapla", 1 milyon kaydı paralel stream ile topla.
5. Optional Sınıfı
Bkz: OptionalOrnekleri.java
- NEDİR? "Değer olabilir VEYA olmayabilir" durumunu temsil eden bir
kapsayıcı (
Optional<T>). Amaç:nullyerine, "değer yok" durumunu tip seviyesinde açıkça belirtmek. - NEDEN GELDİ?
NullPointerException(NPE), Java'nın en sık hatasıdır. Tony Hoare null'ı "milyar dolarlık hata" diye anar. Optional, bir metodun "değer döndürmeyebilirim" demesini imza seviyesinde gösterir. - NE İŞE YARAR: NPE riskini azaltır, niyeti netleştirir, varsayılan değer/ alternatif akış yönetimini kolaylaştırır.
ESKİ vs YENİ:
// ESKİ: null kontrolleri iç içe, unutulursa NPE Kullanici k = bul(id); if (k != null && k.getEmail() != null) { System.out.println(k.getEmail().toUpperCase()); } // YENİ: zincirleme, güvenli String email = bul(id) .map(Kullanici::getEmail) .map(String::toUpperCase) .orElse("EMAIL YOK");
Önemli metotlar: of, ofNullable, empty, isPresent, ifPresent,
map, flatMap, filter, orElse, orElseGet, orElseThrow.
İyi pratik: Optional'ı dönüş tipi olarak kullanın; alan (field) veya metot parametresi olarak kullanmaktan kaçının.
- GERÇEK HAYAT: Banka hesabı bulunamazsa
orElse(0.0)ile güvenli bakiye; kullanıcının e-postası yoksa zincirin güvenle "EMAIL YOK" döndürmesi.
6. Default ve Static Metotlar
Bkz: DefaultStaticMetotlar.java
- NEDİR? Arayüzlerin artık gövdeli metot içerebilmesi:
default(varsayılan uygulama) vestatic(arayüz yardımcısı). - NEDEN GELDİ? Arayüz evrimi (interface evolution) problemi. Bir
arayüze yeni soyut metot eklersen, onu uygulayan tüm mevcut sınıflar bozulur.
Asıl tetikleyici: Stream API.
Collectionarayüzünestream(),forEach(),removeIf()eklenmesi gerekiyordu; bunlar normal metot olsaydı dünyadaki tüm Collection uygulamaları kırılırdı. Default metotlar sayesinde varsayılan gövdeyle eklendiler ve hiçbir mevcut kod bozulmadı. - NE İŞE YARAR: Kütüphane geliştiricilere, kullanıcıları kırmadan arayüze yetenek ekleme imkânı.
Diamond problem: İki arayüzde aynı isimli default metot varsa, uygulayan
sınıf bunu override etmek zorundadır; A.super.metot() ile birini
seçebilir.
- GERÇEK HAYAT:
OdemeYontemiarayüzünde tüm ödeme tiplerinin ücretsiz miras aldığı ortaklogla()default metodu;komisyonHesapla()static yardımcısı.
7. Yeni Date/Time API (java.time)
Bkz: YeniTarihSaatApi.java
-
NEDİR?
LocalDate,LocalTime,LocalDateTime,ZonedDateTime,Duration,Period,Instantgibi modern tarih/saat sınıfları (JSR-310, Joda-Time'dan ilham). -
NEDEN GELDİ? (Eski Date/Calendar'ın sorunları):
- Değiştirilebilir (mutable):
Datethread-safe değildi. - Kafa karıştırıcı API:
Calendar'da ay 0'dan başlardı (Ocak = 0!), yıl 1900 tabanlıydı. Sayısız hataya yol açtı. - Zayıf zaman dilimi yönetimi.
- Zahmetli tarih aritmetiği.
java.timehepsini çözer: değişmez (immutable), thread-safe, akıcı. - Değiştirilebilir (mutable):
ESKİ vs YENİ:
// ESKİ: ay 0-tabanlı! Bu aslında HAZIRAN demek, MAYIS değil Calendar cal = Calendar.getInstance(); cal.set(2026, 5, 24); // YENİ: insan mantığıyla, Haziran = 6 LocalDate tarih = LocalDate.of(2026, 6, 24); LocalDate gelecek = tarih.plusDays(10).plusMonths(2); // immutable, yeni nesne
- NE İŞE YARAR: Yaş hesaplama (
Period), mesai süresi (Duration), zaman dilimi dönüşümü (ZonedDateTime), formatlama/parse (DateTimeFormatter). - GERÇEK HAYAT: Fatura kesim ve son ödeme tarihi hesaplama, doğum gününden yaş çıkarma, İstanbul–New York–Tokyo saat dönüşümü.
8. Nashorn JavaScript Engine
Bkz: NashornOrnekleri.java
- NEDİR? JVM üzerinde JavaScript çalıştıran yüksek performanslı motor
(
javax.script/ JSR-223 üzerinden). - NEDEN GELDİ? Eski "Rhino" motoru yavaş ve eskimişti. Nashorn,
invokedynamicbytecode'unu kullanarak çok daha hızlı çalışır; uygulamalara gömülü scriptleme yeteneği kazandırır. - NE İŞE YARAR: Java'yı yeniden derlemeden dinamik kural/yapılandırma;
kural motorları;
jjskomut satırı aracı.
ÖNEMLİ: Nashorn Java 11'de deprecated, Java 15'te tamamen kaldırıldı. Modern projelerde GraalVM JavaScript tercih edilir. Bu örnek tarihsel/öğretici amaçlıdır ve Java 8–14 ile çalışır.
- GERÇEK HAYAT: İndirim kuralının JavaScript ile tanımlanıp Java kodu değişmeden güncellenebildiği bir kural motoru.
9. Collectors ve Gruplama
Bkz: CollectorsGruplama.java
- NEDİR? Stream'in
collect()işleminde kullanılan hazır toplayıcı "reçeteleri":toList,toSet,toMap,groupingBy,partitioningBy,joining,counting,averagingDouble,summingDouble,mapping,summarizingDouble. - NEDEN GELDİ? "Kategoriye göre grupla" gibi işlemler için elle Map yönetip "anahtar var mı, yoksa yeni liste aç" mantığını tekrar tekrar yazmak gerekiyordu. Collectors bunu tek satıra indirger.
Örnek:
// Departman bazlı çalışan sayısı Map<String, Long> sayilar = calisanlar.stream() .collect(Collectors.groupingBy(c -> c.getDepartman(), Collectors.counting())); // 50.000 üstü / altı ikiye bölme Map<Boolean, List<Calisan>> bolme = calisanlar.stream() .collect(Collectors.partitioningBy(c -> c.getMaas() >= 50000));
- GERÇEK HAYAT: Departman bazlı maaş ortalaması, çok seviyeli gruplama (departman → 40 yaş üstü mü → isimler), müşteri segmentasyonu, raporlama.
10. CompletableFuture (Asenkron Programlama)
Bkz: CompletableFutureOrnekleri.java
- NEDİR? "İleride tamamlanacak bir hesabın sonucunu" temsil eden sınıf. Asenkron işleri başlatır ve sonuçlarını callback'lerle zincirler.
- NEDEN GELDİ? (Eski
Future'ın sorunları):get()ile bloklanmak gerekiyordu; iki future birleştirilemiyordu; otomatik callback ve zincirleme hata yönetimi yoktu. CompletableFuture bunların hepsini çözer. - NE İŞE YARAR: Web servisi/DB/dosya gibi I/O işlerini paralel yürütüp sonuçları birleştirmek; bloklamadan akış kurmak.
Temel metotlar: supplyAsync, thenApply, thenCompose, thenCombine,
thenAccept, exceptionally, allOf, anyOf.
CompletableFuture<Double> toplam = fiyatF.thenCombine(vergiF, (fiyat, vergi) -> fiyat + vergi);
- GERÇEK HAYAT: 3 farklı mikroservisi aynı anda çağırıp (paralel) hepsi bitince sonuçları birleştirmek — toplam süre, en yavaş servis kadar olur (sıralı çağrının toplamı değil).
11. StringJoiner ve String.join
Bkz: StringJoinerOrnekleri.java
- NEDİR?
String.join(...)statik metodu veStringJoinersınıfı; parçaları ayırıcı (delimiter), önek (prefix) ve sonek (suffix) ile birleştirir. - NEDEN GELDİ? "a, b, c" gibi birleştirme çok yaygındı ama standart yolu
yoktu. Geliştiriciler
StringBuilder+ "son elemana virgül koyma" mantığını elle yazıyordu — tekrar eden ve hataya açık (fazladan virgül) kod.
ESKİ vs YENİ:
// ESKİ StringBuilder sb = new StringBuilder(); for (int i = 0; i < list.size(); i++) { sb.append(list.get(i)); if (i < list.size() - 1) sb.append(", "); } // YENİ String s = String.join(", ", list);
- GERÇEK HAYAT: CSV satırı üretme, SQL
IN (...)listesi, URL query string (?k=v&...), rapor etiket listeleri.
12. Repeatable & Type Annotations
Bkz: AnnotationOrnekleri.java
-
Repeatable Annotations:
- NEDİR? Aynı anotasyonu aynı eleman üzerinde birden fazla kez kullanma.
- NEDEN GELDİ? Önceden bir anotasyon bir elemana yalnızca bir kez
konabilirdi; birden fazlası için elle "kapsayıcı (container)" dizi yazmak
gerekiyordu (
@Schedules({@Schedule(...), @Schedule(...)})).@Repeatablebunu temizler.
-
Type Annotations (TYPE_USE):
- NEDİR? Anotasyonların artık tipin kullanıldığı her yere konabilmesi
(
@NonNull String,List<@NonNull String>). - NEDEN GELDİ? Daha güçlü statik analiz / null güvenliği araçları (örn. Checker Framework) için.
- NEDİR? Anotasyonların artık tipin kullanıldığı her yere konabilmesi
(
-
GERÇEK HAYAT: Bir görevin birden fazla çalışma zamanını deklaratif olarak tanımlamak (
@Zamanlamaanotasyonunu Pazartesi/Çarşamba/Cuma için tekrarlama) — cron benzeri zamanlama.
13. Arrays.parallelSort ve PermGen → Metaspace
Bkz: JvmVeYardimcilar.java
A) Arrays.parallelSort
- NEDİR? Diziyi paralel (fork/join havuzu) ile sıralayan metot.
- NEDEN GELDİ?
Arrays.sorttek iş parçacığında çalışır; büyük dizilerde çok çekirdeği kullanmak içinparallelSorteklendi. - DİKKAT: Küçük dizilerde ek yük nedeniyle normal
sortdaha hızlı olabilir.
B) PermGen Kaldırıldı → Metaspace Geldi (JVM değişikliği)
- ESKİ (Java 7 ve öncesi): Sınıf metadata'sı sabit boyutlu PermGen'de
tutulurdu. Çok sınıf yükleyen uygulamalar (uygulama sunucuları, sık deploy
edenler) sıkça
OutOfMemoryError: PermGen spacealırdı.-XX:MaxPermSizeile boyut elle ayarlanırdı, ayarlamak zordu. - YENİ (Java 8): PermGen tamamen kaldırıldı, yerine Metaspace geldi.
- Metaspace heap'te değil, native (yerel) bellekte tutulur.
- Varsayılan olarak otomatik büyür (sınırı işletim sistemi belleği;
-XX:MaxMetaspaceSizeile sınırlanabilir). - Sonuç: "PermGen space" hatası tarihe karıştı; metadata yönetimi daha esnek.
Java 8'e Geçiş: Avantajlar, Dezavantajlar, Riskler
Avantajlar
- Daha az kod, daha okunabilir: Lambda + Stream ile boilerplate ciddi azalır.
- Fonksiyonel paradigma: Deklaratif, niyet-odaklı kod.
- NPE azalması: Optional ile daha güvenli API tasarımı.
- Modern tarih/saat: java.time, eski Date/Calendar dertlerini bitirir.
- Asenkron kolaylığı: CompletableFuture ile bloklamadan paralel akış.
- JVM iyileştirmesi: Metaspace ile PermGen hataları yok; performans artışları.
- Geniş ekosistem: En yaygın LTS olduğu için kütüphane/topluluk desteği güçlü.
Dezavantajlar / Öğrenme Eğrisi
- Zihniyet değişimi: OOP'den fonksiyonele geçiş, ekipler için adaptasyon ister.
- Aşırı kullanım riski: Her şeyi tek satır stream'e sıkıştırmak okunabilirliği bozabilir; karmaşık zincirler debug edilmesi zor olabilir.
- Stack trace okunabilirliği: Lambda/stream hataları bazen kafa karıştırıcı stack trace üretir.
Riskler (Geriye Dönük Uyumluluk & Performans)
- Paralel stream tuzağı: Küçük veride veya paylaşılan değişebilir durumda
(shared mutable state) paralel stream yanlış sonuç veya yavaşlık doğurabilir.
Ortak
ForkJoinPool.commonPool'u tükettiği için dikkatli kullanılmalı. - Optional'ı yanlış kullanma: Field/parametre olarak kullanmak anti-pattern'dir.
- Nashorn bağımlılığı: Nashorn'a bağlı kod, Java 15+'a geçişte kırılır (kaldırıldı). Yeni projelerde kaçınılmalı.
- Geçiş uyumu: Java 8 kodu genelde yeni sürümlere taşınabilir; ancak iç API
(
sun.misc.*), eski tarih API alışkanlıkları ve PermGen flag'leri (-XX:MaxPermSizeartık yok sayılır) gibi noktalarda dikkat gerekir. - Performans: Lambda ilk çağrıda
invokedynamicile bir miktar başlatma maliyeti getirir; sıcak yollarda (hot path) ölçüm yapmak önerilir.
Dosya Listesi ve Çalıştırma
| Dosya | Konu |
|---|---|
LambdaOrnekleri.java | Lambda ifadeleri |
FonksiyonelArayuzler.java | Function/Consumer/Supplier/Predicate/BiFunction + @FunctionalInterface |
MethodReferences.java | Method reference'ların 4 türü |
StreamApiOrnekleri.java | Stream API (map/filter/reduce/collect/flatMap/parallel) |
OptionalOrnekleri.java | Optional ile NPE yönetimi |
DefaultStaticMetotlar.java | Interface'lerde default/static metotlar, diamond problem |
YeniTarihSaatApi.java | java.time (LocalDate, Duration, Period, ZonedDateTime) |
NashornOrnekleri.java | Nashorn JavaScript Engine |
CollectorsGruplama.java | groupingBy/partitioningBy/joining ve toplayıcılar |
CompletableFutureOrnekleri.java | Asenkron programlama |
StringJoinerOrnekleri.java | StringJoiner ve String.join |
AnnotationOrnekleri.java | Repeatable & Type Annotations |
JvmVeYardimcilar.java | Arrays.parallelSort ve PermGen→Metaspace |
Derleme ve Çalıştırma (her dosya bağımsızdır)
# Tek bir dosyayı derleyip çalıştırma: javac LambdaOrnekleri.java java LambdaOrnekleri # Tüm dosyaları derleme: javac *.java # Örnek çalıştırmalar: java StreamApiOrnekleri java YeniTarihSaatApi java CollectorsGruplama
Not:
NashornOrnekleri.javayalnızca Java 8–14 ile anlamlı çıktı verir (Nashorn Java 15'te kaldırıldı). Diğer tüm dosyalar Java 8 ve üzerinde çalışır.
▶ Kod Örnekleri(13)
AnnotationOrnekleri
çalıştırılabilir1import java.lang.annotation.ElementType;
2import java.lang.annotation.Repeatable;
3import java.lang.annotation.Retention;
4import java.lang.annotation.RetentionPolicy;
5import java.lang.annotation.Target;
6import java.util.ArrayList;
7import java.util.List;
8
9/**
10 * ============================================================================
11 * REPEATABLE ANNOTATIONS ve TYPE ANNOTATIONS - Java 8
12 * ============================================================================
13 *
14 * 1) REPEATABLE ANNOTATIONS (Tekrarlanabilir Anotasyonlar)
15 * NEDİR? Aynı anotasyonu aynı eleman üzerinde BİRDEN FAZLA kez kullanabilme.
16 * NEDEN GELDİ? Java 8 öncesinde bir anotasyon bir elemana sadece BİR kez
17 * konabilirdi. Birden fazla değer için elle bir "kapsayıcı (container)"
18 * anotasyon dizisi yazmak gerekiyordu (örn: @Schedules({@Schedule(...),
19 * @Schedule(...)})). Bu çirkin ve zahmetliydi. @Repeatable bunu temizler.
20 *
21 * 2) TYPE ANNOTATIONS (Tip Anotasyonları)
22 * NEDİR? Anotasyonların artık SADECE bildirimlere değil, TİPİN KULLANILDIĞI
23 * her yere konabilmesi (ElementType.TYPE_USE).
24 * NEDEN GELDİ? Daha güçlü statik analiz / null güvenliği araçları (örn:
25 * Checker Framework) için. Örn: @NonNull String, List<@NonNull String>.
26 */
27public class AnnotationOrnekleri {
28
29 public static void main(String[] args) throws Exception {
30
31 System.out.println("=== 1. REPEATABLE ANNOTATION ===\n");
32 // Gorev sinifindaki tekrarlanan @Zamanlama anotasyonlarini oku
33 Zamanlama[] zamanlamalar = Gorev.class.getAnnotationsByType(Zamanlama.class);
34 System.out.println("Gorev uzerindeki zamanlamalar:");
35 for (Zamanlama z : zamanlamalar) {
36 System.out.println(" gun=" + z.gun() + ", saat=" + z.saat());
37 }
38
39 System.out.println("\n=== 2. TYPE ANNOTATION (TYPE_USE) ===\n");
40 // @NotNull bir tip kullanımı üzerinde; çalışma zamanında özel bir etki
41 // yapmaz ama statik analiz araçları bunu okur. Burada sadece derlenip
42 // kod içinde kullanılabildiğini gösteriyoruz.
43 @NotNull String mesaj = "Bu deger null olmamali (statik analiz ipucu)";
44 List<@NotNull String> liste = new ArrayList<>();
45 liste.add("eleman1");
46 liste.add("eleman2");
47 System.out.println("TYPE_USE annotation ile tanimlanan deger: " + mesaj);
48 System.out.println("List<@NotNull String> icerigi: " + liste);
49
50 System.out.println("\n=== 3. GERÇEK HAYAT: Cron benzeri zamanlama ===\n");
51 // Tekrarlanabilir anotasyonlar, bir gorevin birden fazla calisma
52 // zamanini deklaratif olarak tanimlamak icin idealdir.
53 System.out.println("Rapor gorevi su zamanlarda calisacak:");
54 for (Zamanlama z : Gorev.class.getAnnotationsByType(Zamanlama.class)) {
55 System.out.println(" -> Her " + z.gun() + " gunu saat " + z.saat());
56 }
57 }
58
59 // --- Repeatable annotation tanımı ---
60 // @Repeatable, kapsayıcı (container) anotasyonu işaret eder.
61 @Repeatable(Zamanlamalar.class)
62 @Retention(RetentionPolicy.RUNTIME)
63 @Target(ElementType.TYPE)
64 @interface Zamanlama {
65 String gun();
66 String saat();
67 }
68
69 // Kapsayıcı (container) anotasyon - derleyici tekrarları buraya toplar
70 @Retention(RetentionPolicy.RUNTIME)
71 @Target(ElementType.TYPE)
72 @interface Zamanlamalar {
73 Zamanlama[] value();
74 }
75
76 // --- Type annotation tanımı (TYPE_USE) ---
77 @Retention(RetentionPolicy.RUNTIME)
78 @Target(ElementType.TYPE_USE)
79 @interface NotNull {
80 }
81
82 // Aynı anotasyonu birden fazla kez kullanıyoruz (Java 8 öncesi imkansızdı)
83 @Zamanlama(gun = "Pazartesi", saat = "09:00")
84 @Zamanlama(gun = "Carsamba", saat = "14:00")
85 @Zamanlama(gun = "Cuma", saat = "17:30")
86 static class Gorev {
87 }
88}CollectorsGruplama
çalıştırılabilir1import java.util.Arrays;
2import java.util.DoubleSummaryStatistics;
3import java.util.List;
4import java.util.Map;
5import java.util.TreeMap;
6import java.util.stream.Collectors;
7
8/**
9 * ============================================================================
10 * COLLECTORS ve GRUPLAMA (groupingBy / partitioningBy / joining) - Java 8
11 * ============================================================================
12 *
13 * NEDİR?
14 * Collectors, Stream'in collect() terminal işleminde kullanılan HAZIR
15 * "toplayıcı reçeteleridir". Bir akışın elemanlarını listeye, kümeye,
16 * haritaya (Map) toplamayı; gruplamayı; saymayı; ortalama almayı; metne
17 * birleştirmeyi sağlar.
18 *
19 * NEDEN GELDİ?
20 * Eskiden "ürünleri kategoriye göre grupla" gibi bir iş için elle Map
21 * oluşturup, her eleman için "anahtar var mı, yoksa yeni liste aç" mantığını
22 * tekrar tekrar yazmak gerekiyordu. Çok tekrar eden, hataya açık koddu.
23 * Collectors bunları tek satırlık deklaratif ifadelere indirger.
24 *
25 * NE İŞE YARAR / NEREDE: Raporlama, istatistik, kategorize etme, özetleme.
26 * Örn: departman bazlı maaş ortalaması, kategori bazlı stok, müşteri
27 * segmentasyonu.
28 */
29public class CollectorsGruplama {
30
31 public static void main(String[] args) {
32
33 List<Calisan> calisanlar = Arrays.asList(
34 new Calisan("Ahmet", "Yazilim", 45000, 28),
35 new Calisan("Zeynep", "Yazilim", 62000, 35),
36 new Calisan("Mehmet", "Pazarlama", 38000, 41),
37 new Calisan("Ayse", "Pazarlama", 52000, 30),
38 new Calisan("Burak", "Finans", 71000, 45),
39 new Calisan("Elif", "Yazilim", 48000, 26));
40
41 System.out.println("=== 1. toList / toSet / toMap ===\n");
42 List<String> isimler = calisanlar.stream()
43 .map(c -> c.isim)
44 .collect(Collectors.toList());
45 System.out.println("Isimler (List): " + isimler);
46
47 // toMap: isim -> maas haritası
48 Map<String, Double> isimMaas = calisanlar.stream()
49 .collect(Collectors.toMap(c -> c.isim, c -> c.maas));
50 System.out.println("Isim->Maas (Map): " + isimMaas);
51
52 System.out.println("\n=== 2. groupingBy : Anahtara göre gruplama ===\n");
53 // ESKİ YÖNTEM elle Map yönetmek gerekirdi; YENİ tek satır:
54 Map<String, List<Calisan>> departmana = calisanlar.stream()
55 .collect(Collectors.groupingBy(c -> c.departman));
56 departmana.forEach((dep, liste) -> {
57 System.out.println(dep + ":");
58 liste.forEach(c -> System.out.println(" " + c.isim));
59 });
60
61 System.out.println("\n=== 3. groupingBy + counting : Grup sayıları ===\n");
62 Map<String, Long> departmanSayilari = calisanlar.stream()
63 .collect(Collectors.groupingBy(c -> c.departman, Collectors.counting()));
64 System.out.println("Departman bazli calisan sayisi: " + departmanSayilari);
65
66 System.out.println("\n=== 4. groupingBy + averagingDouble : Grup ortalaması ===\n");
67 Map<String, Double> departmanMaasOrt = calisanlar.stream()
68 .collect(Collectors.groupingBy(c -> c.departman,
69 Collectors.averagingDouble(c -> c.maas)));
70 departmanMaasOrt.forEach((dep, ort) ->
71 System.out.printf("%-12s ortalama maas: %.2f TL%n", dep, ort));
72
73 System.out.println("\n=== 5. groupingBy + summingDouble / mapping ===\n");
74 // Departman bazlı toplam maaş
75 Map<String, Double> toplamMaas = calisanlar.stream()
76 .collect(Collectors.groupingBy(c -> c.departman,
77 Collectors.summingDouble(c -> c.maas)));
78 System.out.println("Departman toplam maas: " + toplamMaas);
79
80 // groupingBy + mapping: departmana göre SADECE isimleri topla
81 Map<String, List<String>> departmanIsimleri = calisanlar.stream()
82 .collect(Collectors.groupingBy(c -> c.departman,
83 Collectors.mapping(c -> c.isim, Collectors.toList())));
84 System.out.println("Departman isimleri: " + departmanIsimleri);
85
86 System.out.println("\n=== 6. partitioningBy : İkiye bölme (true/false) ===\n");
87 // Maaşı 50000'den yüksek olanlar / olmayanlar
88 Map<Boolean, List<Calisan>> bolme = calisanlar.stream()
89 .collect(Collectors.partitioningBy(c -> c.maas >= 50000));
90 System.out.println("Yuksek maaslilar (>=50000):");
91 bolme.get(true).forEach(c -> System.out.println(" " + c.isim + " - " + c.maas));
92 System.out.println("Dusuk maaslilar (<50000):");
93 bolme.get(false).forEach(c -> System.out.println(" " + c.isim + " - " + c.maas));
94
95 System.out.println("\n=== 7. joining : Metinleri birleştirme ===\n");
96 String tumIsimler = calisanlar.stream()
97 .map(c -> c.isim)
98 .collect(Collectors.joining(", ", "[", "]")); // ayirici, onek, sonek
99 System.out.println("Birlestirilmis: " + tumIsimler);
100
101 System.out.println("\n=== 8. summarizingDouble : Tek seferde istatistik ===\n");
102 DoubleSummaryStatistics maasIstatistik = calisanlar.stream()
103 .collect(Collectors.summarizingDouble(c -> c.maas));
104 System.out.println("Calisan sayisi : " + maasIstatistik.getCount());
105 System.out.println("Toplam maas : " + maasIstatistik.getSum());
106 System.out.println("Ortalama : " + maasIstatistik.getAverage());
107 System.out.println("En yuksek : " + maasIstatistik.getMax());
108 System.out.println("En dusuk : " + maasIstatistik.getMin());
109
110 System.out.println("\n=== 9. GERÇEK HAYAT: Çok seviyeli gruplama ===\n");
111 // Departman -> (40 yaş üstü mü?) -> isimler
112 Map<String, Map<Boolean, List<String>>> cokSeviyeli = calisanlar.stream()
113 .collect(Collectors.groupingBy(
114 c -> c.departman,
115 Collectors.groupingBy(
116 c -> c.yas >= 40,
117 Collectors.mapping(c -> c.isim, Collectors.toList()))));
118 cokSeviyeli.forEach((dep, yasMap) -> {
119 System.out.println(dep + ":");
120 System.out.println(" 40+ : " + yasMap.getOrDefault(true, Arrays.asList()));
121 System.out.println(" <40 : " + yasMap.getOrDefault(false, Arrays.asList()));
122 });
123
124 System.out.println("\n=== 10. Sıralı grup (TreeMap supplier) ===\n");
125 // groupingBy ile harita tipini TreeMap olarak belirleyip alfabetik sirala
126 Map<String, Long> sirali = calisanlar.stream()
127 .collect(Collectors.groupingBy(c -> c.departman,
128 TreeMap::new, Collectors.counting()));
129 System.out.println("Alfabetik sirali departmanlar: " + sirali);
130 }
131
132 static class Calisan {
133 String isim, departman;
134 double maas;
135 int yas;
136
137 Calisan(String isim, String departman, double maas, int yas) {
138 this.isim = isim;
139 this.departman = departman;
140 this.maas = maas;
141 this.yas = yas;
142 }
143 }
144}CompletableFutureOrnekleri
çalıştırılabilir1import java.util.Arrays;
2import java.util.List;
3import java.util.concurrent.CompletableFuture;
4import java.util.concurrent.ExecutionException;
5import java.util.concurrent.ExecutorService;
6import java.util.concurrent.Executors;
7import java.util.stream.Collectors;
8
9/**
10 * ============================================================================
11 * CompletableFuture - ASENKRON PROGRAMLAMA - Java 8
12 * ============================================================================
13 *
14 * NEDİR?
15 * CompletableFuture<T>, "ileride tamamlanacak bir hesabın sonucunu" temsil
16 * eden bir sınıftır. Asenkron (eş zamanlı olmayan) işleri başlatır ve
17 * sonuçlarını ZİNCİRLEYEREK (callback'lerle) işlemeyi sağlar.
18 *
19 * NEDEN GELDİ? (Eski Future'ın sorunları)
20 * Java 5'teki java.util.concurrent.Future yetersizdi:
21 * - Sonucu almak için get() ile BLOKLANMAK gerekiyordu (thread bekler).
22 * - İki future'ı birleştirmek (combine) mümkün değildi.
23 * - Tamamlandığında otomatik callback çalıştırılamıyordu.
24 * - Hata yönetimi (exception handling) zincirleme yapılamıyordu.
25 *
26 * CompletableFuture bunların hepsini çözer: bloklamadan, zincirleyerek,
27 * hataları yöneterek asenkron akışlar kurarsın.
28 *
29 * NE İŞE YARAR: Web servis çağrıları, veritabanı sorguları, dosya okuma gibi
30 * I/O ağırlıklı işleri paralel yürütüp sonuçları birleştirme.
31 *
32 * TEMEL METOTLAR:
33 * supplyAsync : asenkron başlat (değer üretir)
34 * thenApply : sonucu dönüştür (map gibi)
35 * thenCompose : başka bir future ile zincirle (flatMap gibi)
36 * thenCombine : iki future'ı birleştir
37 * thenAccept : sonucu tüket (Consumer)
38 * exceptionally: hata olursa yedek değer
39 * allOf/anyOf : birden fazla future'ı bekle
40 */
41public class CompletableFutureOrnekleri {
42
43 public static void main(String[] args) throws Exception {
44
45 System.out.println("=== 1. supplyAsync + thenApply + thenAccept ===\n");
46 CompletableFuture<String> akis = CompletableFuture
47 .supplyAsync(() -> {
48 uyut(300);
49 return "ham veri";
50 })
51 .thenApply(veri -> veri.toUpperCase()) // dönüştür
52 .thenApply(veri -> "[islenmis] " + veri); // tekrar dönüştür
53 // thenAccept ile sonucu tüket (geri dönüş yok)
54 akis.thenAccept(sonuc -> System.out.println("Sonuc: " + sonuc));
55 akis.join(); // demo için ana thread'in bitmesini beklet
56
57 System.out.println("\n=== 2. thenCombine : İki asenkron işi birleştir ===\n");
58 // Senaryo: Fiyat servisi ve vergi servisi paralel calisir, sonra toplanir
59 CompletableFuture<Double> fiyatF = CompletableFuture.supplyAsync(() -> {
60 uyut(200);
61 System.out.println(" Fiyat servisi tamam");
62 return 1000.0;
63 });
64 CompletableFuture<Double> vergiF = CompletableFuture.supplyAsync(() -> {
65 uyut(250);
66 System.out.println(" Vergi servisi tamam");
67 return 180.0;
68 });
69 CompletableFuture<Double> toplamF = fiyatF.thenCombine(vergiF,
70 (fiyat, vergi) -> fiyat + vergi);
71 System.out.println("Toplam (fiyat+vergi): " + toplamF.get() + " TL");
72
73 System.out.println("\n=== 3. thenCompose : Bağımlı asenkron zincir ===\n");
74 // Önce kullanıcı id'sini al, SONRA o id ile siparişleri çek (sıralı bağımlılık)
75 CompletableFuture<String> siparisler = kullaniciIdGetir("ahmet")
76 .thenCompose(id -> siparisleriGetir(id));
77 System.out.println(siparisler.get());
78
79 System.out.println("\n=== 4. exceptionally : Hata yönetimi ===\n");
80 CompletableFuture<Integer> hataliAkis = CompletableFuture
81 .<Integer>supplyAsync(() -> {
82 throw new RuntimeException("Servis cokmesi!");
83 })
84 .exceptionally(ex -> {
85 System.out.println(" Hata yakalandi: " + ex.getMessage());
86 return -1; // yedek (fallback) deger
87 });
88 System.out.println("Hatadan sonra deger: " + hataliAkis.get());
89
90 System.out.println("\n=== 5. allOf : Birden fazla işi paralel bekle ===\n");
91 // 3 farklı servisi aynı anda çağır, hepsi bitince devam et
92 long baslangic = System.currentTimeMillis();
93 CompletableFuture<String> s1 = servisCagir("Servis-A", 300);
94 CompletableFuture<String> s2 = servisCagir("Servis-B", 200);
95 CompletableFuture<String> s3 = servisCagir("Servis-C", 400);
96
97 CompletableFuture<Void> hepsi = CompletableFuture.allOf(s1, s2, s3);
98 hepsi.join(); // hepsi bitene kadar bekle
99
100 // Sonuçları topla
101 List<String> sonuclar = Arrays.asList(s1, s2, s3).stream()
102 .map(CompletableFuture::join)
103 .collect(Collectors.toList());
104 long sure = System.currentTimeMillis() - baslangic;
105 System.out.println("Tum servisler tamam: " + sonuclar);
106 // 300+200+400=900ms degil; paralel oldugu icin ~400ms (en yavasi kadar)
107 System.out.println("Toplam sure (paralel): ~" + sure + " ms (sirali olsa ~900ms)");
108
109 System.out.println("\n=== 6. Özel ExecutorService ile ===\n");
110 ExecutorService havuz = Executors.newFixedThreadPool(2);
111 CompletableFuture<String> ozel = CompletableFuture.supplyAsync(() -> {
112 return "Ozel thread havuzunda calisti: " + Thread.currentThread().getName();
113 }, havuz);
114 System.out.println(ozel.get());
115 havuz.shutdown();
116 }
117
118 static CompletableFuture<String> kullaniciIdGetir(String kullaniciAdi) {
119 return CompletableFuture.supplyAsync(() -> {
120 uyut(150);
121 return "ID-" + kullaniciAdi.hashCode();
122 });
123 }
124
125 static CompletableFuture<String> siparisleriGetir(String id) {
126 return CompletableFuture.supplyAsync(() -> {
127 uyut(150);
128 return id + " icin siparisler: [S100, S101, S102]";
129 });
130 }
131
132 static CompletableFuture<String> servisCagir(String ad, int gecikme) {
133 return CompletableFuture.supplyAsync(() -> {
134 uyut(gecikme);
135 return ad + "(" + gecikme + "ms)";
136 });
137 }
138
139 static void uyut(long ms) {
140 try {
141 Thread.sleep(ms);
142 } catch (InterruptedException e) {
143 Thread.currentThread().interrupt();
144 }
145 }
146}DefaultStaticMetotlar
çalıştırılabilir1/**
2 * ============================================================================
3 * INTERFACE'LERDE DEFAULT ve STATIC METOTLAR - Java 8
4 * ============================================================================
5 *
6 * NEDİR?
7 * Java 8 ile arayüzler (interface), gövdesi olan iki yeni metot türü
8 * içerebilir:
9 * - default metot : Bir varsayılan uygulama (implementation) sağlar.
10 * Uygulayan sınıflar override etmek zorunda DEĞİLDİR.
11 * - static metot : Arayüze bağlı yardımcı (utility) metot. Örnek üzerinden
12 * değil, arayüz adıyla çağrılır.
13 *
14 * NEDEN GELDİ? (Hangi problemi çözdü?)
15 * "Interface Evolution" (arayüz evrimi) problemi: Bir arayüzü yayınladıktan
16 * sonra yeni bir metot eklersen, o arayüzü uygulayan TÜM mevcut sınıflar
17 * derlenemez hale gelirdi (her birine metodu eklemek gerekirdi). Bu, geriye
18 * dönük uyumluluğu bozardı.
19 *
20 * Asıl tetikleyici: Java 8'in Stream API'si. List, Collection gibi mevcut
21 * arayüzlere forEach(), stream(), removeIf() gibi metotlar eklenmesi
22 * gerekiyordu. Eğer bunlar normal (soyut) metot olsaydı, dünyadaki tüm
23 * Collection uygulamaları bozulurdu. DEFAULT metotlar sayesinde bu metotlar
24 * varsayılan gövdeyle eklendi ve hiçbir mevcut kod bozulmadı.
25 *
26 * NE İŞE YARAR: Kütüphane geliştiricilerine, mevcut kullanıcıları kırmadan
27 * arayüzlere yeni yetenek ekleme imkânı verir.
28 */
29public class DefaultStaticMetotlar {
30
31 public static void main(String[] args) {
32
33 System.out.println("=== 1. default Metot: Varsayılan Uygulama ===\n");
34 Arac araba = new Araba();
35 araba.calistir(); // Araba'nin kendi (override) uygulamasi
36 araba.kornaCal(); // arayuzden gelen DEFAULT uygulama
37
38 Arac bisiklet = new Bisiklet();
39 bisiklet.calistir();
40 bisiklet.kornaCal(); // Bisiklet bunu OVERRIDE etti
41
42 System.out.println("\n=== 2. static Metot: Arayüz Yardımcısı ===\n");
43 // Arayüz adıyla çağrılır, örnek gerekmez
44 System.out.println(Arac.aracTipiAciklamasi());
45
46 System.out.println("\n=== 3. GERÇEK HAYAT: Ödeme yöntemleri ===\n");
47 OdemeYontemi krediKarti = new KrediKarti();
48 OdemeYontemi havale = new Havale();
49
50 krediKarti.ode(1000);
51 // logla() -> arayuzden gelen ortak default davranis (her ikisi de kullanir)
52 krediKarti.logla(1000);
53 havale.ode(500);
54 havale.logla(500);
55
56 // static metot: komisyon hesaplama yardımcısı
57 System.out.println("1000 TL icin standart komisyon: "
58 + OdemeYontemi.komisyonHesapla(1000) + " TL");
59
60 System.out.println("\n=== 4. Çoklu Kalıtım Çakışması (Diamond Problem) ===\n");
61 // A ve B arayüzlerinin ikisinde de aynı isimli default metot var.
62 // C sınıfı bunu çözmek için override etmek ZORUNDADIR (derleyici zorlar).
63 C c = new C();
64 c.selam(); // C'nin cozumledigi versiyon
65 }
66
67 /** default ve static metot içeren arayüz. */
68 interface Arac {
69 // Soyut metot (uygulayan sınıf MUTLAKA yazmalı)
70 void calistir();
71
72 // DEFAULT metot: gövdeli, override zorunlu değil
73 default void kornaCal() {
74 System.out.println(" Bip bip! (varsayilan korna)");
75 }
76
77 // STATIC metot: arayuz duzeyinde yardimci
78 static String aracTipiAciklamasi() {
79 return "Bu bir kara tasiti arayuzudur.";
80 }
81 }
82
83 static class Araba implements Arac {
84 @Override
85 public void calistir() {
86 System.out.println("Araba motoru calisti (vroom).");
87 }
88 // kornaCal override edilmedi -> default kullanilir
89 }
90
91 static class Bisiklet implements Arac {
92 @Override
93 public void calistir() {
94 System.out.println("Bisiklet pedallari donuyor.");
95 }
96 @Override
97 public void kornaCal() {
98 System.out.println(" Cling cling! (bisiklet zili - override)");
99 }
100 }
101
102 interface OdemeYontemi {
103 void ode(double tutar);
104
105 // Ortak loglama davranışı - tüm ödeme yöntemleri ücretsiz miras alır
106 default void logla(double tutar) {
107 System.out.println(" [LOG] " + tutar + " TL odeme kaydedildi.");
108 }
109
110 static double komisyonHesapla(double tutar) {
111 return tutar * 0.015; // %1.5 standart komisyon
112 }
113 }
114
115 static class KrediKarti implements OdemeYontemi {
116 @Override
117 public void ode(double tutar) {
118 System.out.println("Kredi karti ile " + tutar + " TL odendi.");
119 }
120 }
121
122 static class Havale implements OdemeYontemi {
123 @Override
124 public void ode(double tutar) {
125 System.out.println("Havale/EFT ile " + tutar + " TL gonderildi.");
126 }
127 }
128
129 // --- Diamond problem örneği ---
130 interface A {
131 default void selam() { System.out.println("A'dan selam"); }
132 }
133 interface B {
134 default void selam() { System.out.println("B'den selam"); }
135 }
136 // Hem A hem B'yi uygular; iki default metot çakışır -> override ZORUNLU
137 static class C implements A, B {
138 @Override
139 public void selam() {
140 A.super.selam(); // istersek belirli birini çağırabiliriz
141 B.super.selam();
142 System.out.println("C, cakismayi cozumledi.");
143 }
144 }
145}FonksiyonelArayuzler
çalıştırılabilir1import java.util.Arrays;
2import java.util.List;
3import java.util.function.BiFunction;
4import java.util.function.BinaryOperator;
5import java.util.function.Consumer;
6import java.util.function.Function;
7import java.util.function.Predicate;
8import java.util.function.Supplier;
9import java.util.function.UnaryOperator;
10
11/**
12 * ============================================================================
13 * FONKSİYONEL ARAYÜZLER (FUNCTIONAL INTERFACES) - Java 8
14 * ============================================================================
15 *
16 * NEDİR?
17 * İçinde TEK BİR soyut metot bulunan arayüzdür (Single Abstract Method - SAM).
18 * Lambda ifadeleri ve method reference'lar, ancak bir fonksiyonel arayüz
19 * tipine atanabilir. Yani lambda'nın "tipi" daima bir fonksiyonel arayüzdür.
20 *
21 * @FunctionalInterface anotasyonu derleyiciye "bu arayüzde tam olarak 1 soyut
22 * metot olmalı" der; yanlışlıkla ikinci bir soyut metot eklenirse DERLEME
23 * HATASI verir. (Zorunlu değildir ama tavsiye edilir.)
24 *
25 * NEDEN GELDİ?
26 * Java zaten Runnable, Comparator, Callable gibi tek metotlu arayüzlere
27 * sahipti ama her ihtiyaç için yeni arayüz tanımlamak zahmetliydi. Java 8,
28 * java.util.function paketinde HAZIR, genel amaçlı fonksiyonel arayüzler
29 * getirdi. Böylece kendi arayüzünü yazmadan davranış geçirebilirsin.
30 *
31 * EN ÇOK KULLANILANLAR:
32 * - Function<T,R> : T alır, R döndürür (apply)
33 * - Consumer<T> : T alır, hiçbir şey döndürmez (accept)
34 * - Supplier<T> : Parametre almaz, T üretir (get)
35 * - Predicate<T> : T alır, boolean döndürür (test)
36 * - BiFunction<T,U,R> : İki girdi (T,U), R döndürür (apply)
37 * - UnaryOperator<T> : T alır, T döndürür (Function özel hali)
38 * - BinaryOperator<T> : İki T alır, T döndürür (BiFunction özel hali)
39 */
40public class FonksiyonelArayuzler {
41
42 public static void main(String[] args) {
43
44 System.out.println("=== 1. Function<T,R> : Dönüştürme ===\n");
45 // Bir String'i uzunluğuna dönüştür
46 Function<String, Integer> uzunluk = s -> s.length();
47 System.out.println("'Merhaba' uzunlugu: " + uzunluk.apply("Merhaba"));
48
49 // andThen / compose ile fonksiyon zincirleme
50 Function<Integer, Integer> ikiyleCarp = x -> x * 2;
51 Function<Integer, Integer> birEkle = x -> x + 1;
52 // önce çarp sonra ekle: (5*2)+1 = 11
53 System.out.println("andThen (carp->ekle): " + ikiyleCarp.andThen(birEkle).apply(5));
54 // önce ekle sonra çarp: (5+1)*2 = 12
55 System.out.println("compose (ekle->carp): " + ikiyleCarp.compose(birEkle).apply(5));
56
57 System.out.println("\n=== 2. Consumer<T> : Tüketme (yan etki) ===\n");
58 Consumer<String> yazdir = s -> System.out.println("Tuketildi: " + s);
59 yazdir.accept("Java 8");
60 // andThen ile iki consumer'ı sırayla çalıştır
61 Consumer<String> buyukYaz = s -> System.out.println("BUYUK: " + s.toUpperCase());
62 yazdir.andThen(buyukYaz).accept("zincir");
63
64 System.out.println("\n=== 3. Supplier<T> : Üretme ===\n");
65 Supplier<Double> rastgele = () -> Math.random();
66 System.out.println("Rastgele uretildi: " + rastgele.get());
67 // Lazy (tembel) değer üretiminde çok kullanışlıdır.
68
69 System.out.println("\n=== 4. Predicate<T> : Koşul testi ===\n");
70 Predicate<Integer> ciftMi = n -> n % 2 == 0;
71 Predicate<Integer> pozitifMi = n -> n > 0;
72 System.out.println("4 cift mi? " + ciftMi.test(4));
73 // and / or / negate ile birleştirme
74 System.out.println("6 cift VE pozitif? " + ciftMi.and(pozitifMi).test(6));
75 System.out.println("-3 cift DEGIL mi? " + ciftMi.negate().test(-3));
76
77 System.out.println("\n=== 5. BiFunction<T,U,R> : İki girdi ===\n");
78 BiFunction<Integer, Integer, Integer> topla = (a, b) -> a + b;
79 System.out.println("3 + 4 = " + topla.apply(3, 4));
80 BiFunction<String, String, String> birlestir = (a, b) -> a + " " + b;
81 System.out.println(birlestir.apply("Merhaba", "Dunya"));
82
83 System.out.println("\n=== 6. UnaryOperator & BinaryOperator ===\n");
84 UnaryOperator<String> kucult = s -> s.toLowerCase();
85 System.out.println("Kucult: " + kucult.apply("JAVA"));
86 BinaryOperator<Integer> maks = (a, b) -> a > b ? a : b;
87 System.out.println("Maks(10, 25): " + maks.apply(10, 25));
88
89 System.out.println("\n=== 7. GERÇEK HAYAT: Ürün Filtreleme (E-ticaret) ===\n");
90 List<Urun> urunler = Arrays.asList(
91 new Urun("Telefon", 15000, true),
92 new Urun("Kulaklik", 800, false),
93 new Urun("Laptop", 32000, true),
94 new Urun("Mouse", 350, true));
95
96 // Predicate'leri yeniden kullanılabilir kurallar olarak tanımla
97 Predicate<Urun> stokta = u -> u.stoktaVar;
98 Predicate<Urun> pahali = u -> u.fiyat > 1000;
99
100 System.out.println("Stokta OLAN ve PAHALI urunler:");
101 for (Urun u : urunler) {
102 // İş kurallarını birleştir: stokta VE pahalı
103 if (stokta.and(pahali).test(u)) {
104 System.out.println(" " + u);
105 }
106 }
107
108 // Function ile vergi hesaplama kuralı
109 Function<Urun, Double> kdvliFiyat = u -> u.fiyat * 1.20;
110 System.out.println("\nKDV'li fiyatlar:");
111 urunler.forEach(u ->
112 System.out.printf(" %-10s : %.2f TL%n", u.ad, kdvliFiyat.apply(u)));
113
114 System.out.println("\n=== 8. ÖZEL @FunctionalInterface Tanımlama ===\n");
115 IndirimKurali yuzde10 = fiyat -> fiyat * 0.90;
116 IndirimKurali sabit50 = fiyat -> fiyat - 50;
117 System.out.println("1000 TL'ye %10 indirim: " + yuzde10.uygula(1000));
118 System.out.println("1000 TL'ye 50 TL indirim: " + sabit50.uygula(1000));
119 }
120
121 /**
122 * Kendi fonksiyonel arayüzümüz. @FunctionalInterface sayesinde ikinci bir
123 * soyut metot eklersek derleyici hata verir (güvenlik).
124 */
125 @FunctionalInterface
126 interface IndirimKurali {
127 double uygula(double fiyat);
128 }
129
130 static class Urun {
131 String ad;
132 double fiyat;
133 boolean stoktaVar;
134
135 Urun(String ad, double fiyat, boolean stoktaVar) {
136 this.ad = ad;
137 this.fiyat = fiyat;
138 this.stoktaVar = stoktaVar;
139 }
140
141 @Override
142 public String toString() {
143 return ad + " - " + fiyat + " TL (stok: " + (stoktaVar ? "var" : "yok") + ")";
144 }
145 }
146}JvmVeYardimcilar
çalıştırılabilir1import java.util.Arrays;
2import java.util.Random;
3
4/**
5 * ============================================================================
6 * JVM DEĞİŞİKLİKLERİ ve YARDIMCI YENİLİKLER - Java 8
7 * ============================================================================
8 *
9 * Bu dosya iki konuyu örnekler:
10 * A) Arrays.parallelSort : Büyük dizileri çoklu çekirdekte sıralama
11 * B) PermGen -> Metaspace : JVM bellek modeli değişikliği (anlatım + kanıt)
12 *
13 * ----------------------------------------------------------------------------
14 * A) Arrays.parallelSort
15 * NEDİR? Diziyi paralel (fork/join havuzu ile) sıralayan metot.
16 * NEDEN GELDİ? Arrays.sort tek iş parçacığında çalışır. Çok büyük dizilerde
17 * çok çekirdekli işlemcileri kullanmak için parallelSort eklendi.
18 * NE İŞE YARAR: Büyük veri kümelerinde sıralamayı hızlandırır.
19 * DİKKAT: Küçük dizilerde ek yük nedeniyle normal sort daha hızlı olabilir.
20 *
21 * ----------------------------------------------------------------------------
22 * B) PermGen Kaldırıldı -> Metaspace Geldi (JVM iç değişikliği)
23 * ESKİ (Java 7 ve öncesi): PermGen (Permanent Generation) adında SABİT
24 * boyutlu bir bellek alanı vardı. Sınıf metadata'sı (yüklenen sınıf
25 * bilgileri) burada tutulurdu. Çok sayıda sınıf yükleyen uygulamalarda
26 * (özellikle uygulama sunucuları, sık deploy yapan sistemler) sıkça
27 * "java.lang.OutOfMemoryError: PermGen space" hatası alınırdı.
28 * -XX:MaxPermSize ile boyut elle ayarlanırdı; ayarlamak zordu.
29 *
30 * YENİ (Java 8): PermGen tamamen KALDIRILDI. Yerine METASPACE geldi.
31 * - Metaspace, JVM heap'inde DEĞİL, yerel (native) bellekte tutulur.
32 * - Varsayılan olarak boyutu OTOMATİK büyür (sınırı yalnızca işletim
33 * sistemi belleğidir; -XX:MaxMetaspaceSize ile sınırlanabilir).
34 * - Sonuç: "PermGen space" hatası tarihe karıştı; sınıf metadata yönetimi
35 * daha esnek ve daha az sorunlu hale geldi.
36 */
37public class JvmVeYardimcilar {
38
39 public static void main(String[] args) {
40
41 System.out.println("=== A) Arrays.parallelSort vs Arrays.sort ===\n");
42
43 int boyut = 2_000_000;
44 int[] dizi1 = rastgeleDizi(boyut);
45 int[] dizi2 = Arrays.copyOf(dizi1, dizi1.length); // ayni veri
46
47 // ESKİ/Klasik: tek iş parçacıklı sort
48 long t1 = System.currentTimeMillis();
49 Arrays.sort(dizi1);
50 long sureSort = System.currentTimeMillis() - t1;
51
52 // YENİ: paralel sort (fork/join)
53 long t2 = System.currentTimeMillis();
54 Arrays.parallelSort(dizi2);
55 long sureParalel = System.currentTimeMillis() - t2;
56
57 System.out.println("Dizi boyutu : " + boyut);
58 System.out.println("Arrays.sort : " + sureSort + " ms");
59 System.out.println("Arrays.parallelSort: " + sureParalel + " ms");
60 System.out.println("Cekirdek sayisi : " + Runtime.getRuntime().availableProcessors());
61 System.out.println("Iki sonuc esit mi? : " + Arrays.equals(dizi1, dizi2));
62 System.out.println("(Not: kucuk dizilerde paralel daha YAVAS olabilir.)");
63
64 System.out.println("\n=== B) PermGen -> Metaspace (JVM bellek bilgisi) ===\n");
65 // Çalışılan JVM sürümü hakkında bilgi - Java 8'de PermGen yoktur
66 System.out.println("Java surumu : " + System.getProperty("java.version"));
67 System.out.println("JVM adi : " + System.getProperty("java.vm.name"));
68
69 long maxHeap = Runtime.getRuntime().maxMemory();
70 System.out.printf("Max heap (yaklasik): %.0f MB%n", maxHeap / (1024.0 * 1024.0));
71
72 System.out.println();
73 System.out.println("Java 7'de sinif metadata'si SABIT boyutlu PermGen'de tutulurdu");
74 System.out.println("ve 'OutOfMemoryError: PermGen space' sik gorulurdu.");
75 System.out.println("Java 8'de PermGen kaldirildi; metadata artik native bellekteki");
76 System.out.println("METASPACE'te tutulur ve otomatik buyur. Bu hata tarihe karisti.");
77 }
78
79 static int[] rastgeleDizi(int boyut) {
80 Random r = new Random(42); // sabit tohum -> tekrarlanabilir
81 int[] dizi = new int[boyut];
82 for (int i = 0; i < boyut; i++) {
83 dizi[i] = r.nextInt();
84 }
85 return dizi;
86 }
87}LambdaOrnekleri
çalıştırılabilir1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.Collections;
4import java.util.Comparator;
5import java.util.List;
6import java.util.function.Function;
7
8/**
9 * ============================================================================
10 * LAMBDA İFADELERİ (LAMBDA EXPRESSIONS) - Java 8
11 * ============================================================================
12 *
13 * NEDİR?
14 * Lambda ifadesi, isimsiz (anonim) bir fonksiyondur. Kısaca "bir metodu,
15 * bir nesneye sarmadan, doğrudan davranış olarak geçirme" yöntemidir.
16 *
17 * Sözdizimi: (parametreler) -> { gövde }
18 * Örnek: (a, b) -> a + b
19 *
20 * NEDEN GELDİ? (Hangi problemi çözdü?)
21 * Java 8 öncesinde bir davranışı (kod parçasını) bir metoda geçirmek için
22 * ANONİM İÇ SINIF (anonymous inner class) yazmak zorundaydık. Bu çok
23 * gürültülü (boilerplate) koda yol açıyordu. 1 satırlık iş için 5-6 satır
24 * tören kodu yazmak gerekiyordu.
25 *
26 * NE İŞE YARAR / NEREDE KOLAYLIK SAĞLAR?
27 * - Koleksiyonları sıralama (Comparator)
28 * - Olay dinleyicileri (event listener)
29 * - Stream API ile birlikte filtreleme/dönüştürme
30 * - Çok kısa, okunabilir, fonksiyonel kod
31 */
32public class LambdaOrnekleri {
33
34 public static void main(String[] args) {
35
36 System.out.println("=== 1. ESKİ YÖNTEM vs YENİ YÖNTEM: Comparator ===\n");
37
38 List<String> isimler = new ArrayList<>(
39 Arrays.asList("Zeynep", "Ahmet", "Mehmet", "Ayse", "Burak"));
40
41 // ESKİ YÖNTEM (Java 7 ve öncesi): Anonim iç sınıf
42 // Sadece "iki ismi karşılaştır" demek için 5 satır boilerplate kod.
43 Collections.sort(isimler, new Comparator<String>() {
44 @Override
45 public int compare(String a, String b) {
46 return a.compareTo(b);
47 }
48 });
49 System.out.println("Eski yöntemle siralandi : " + isimler);
50
51 // YENİ YÖNTEM (Java 8): Lambda ifadesi - tek satır
52 Collections.sort(isimler, (a, b) -> b.compareTo(a)); // ters sıralama
53 System.out.println("Lambda ile siralandi : " + isimler);
54
55 System.out.println("\n=== 2. Lambda Sözdizimi Çeşitleri ===\n");
56
57 // Parametresiz lambda
58 Runnable selam = () -> System.out.println("Merhaba Lambda dunyasi!");
59 selam.run();
60
61 // Tek parametreli (parantez opsiyonel)
62 Function<Integer, Integer> kare = x -> x * x;
63 System.out.println("5'in karesi: " + kare.apply(5));
64
65 // Çok parametreli + çok satırlı gövde (blok)
66 Hesaplama topla = (a, b) -> {
67 int sonuc = a + b;
68 System.out.println(a + " + " + b + " hesaplaniyor...");
69 return sonuc;
70 };
71 System.out.println("Sonuc: " + topla.hesapla(7, 8));
72
73 System.out.println("\n=== 3. GERÇEK HAYAT ÖRNEĞİ: Çalışan Listesi Sıralama ===\n");
74
75 List<Calisan> calisanlar = Arrays.asList(
76 new Calisan("Ahmet", "Yazilim", 45000),
77 new Calisan("Zeynep", "Pazarlama", 52000),
78 new Calisan("Mehmet", "Yazilim", 38000),
79 new Calisan("Ayse", "Finans", 61000));
80
81 // Maaşa göre artan sıralama (lambda + Comparator)
82 calisanlar.sort((c1, c2) -> Double.compare(c1.maas, c2.maas));
83 System.out.println("Maasa gore artan:");
84 calisanlar.forEach(c -> System.out.println(" " + c));
85
86 // Comparator.comparing ile daha da okunabilir (method reference önizleme)
87 calisanlar.sort(Comparator.comparing((Calisan c) -> c.departman)
88 .thenComparing(c -> c.isim));
89 System.out.println("\nDepartman, sonra isme gore:");
90 calisanlar.forEach(c -> System.out.println(" " + c));
91
92 System.out.println("\n=== 4. forEach ile Lambda (Iterable.forEach) ===\n");
93 // ESKİ YÖNTEM: for döngüsü
94 for (Calisan c : calisanlar) {
95 System.out.println("Eski for: " + c.isim);
96 }
97 // YENİ YÖNTEM: forEach + lambda
98 calisanlar.forEach(c -> System.out.println("Lambda forEach: " + c.isim));
99
100 System.out.println("\n=== 5. Effectively Final (Kapanış / Closure) ===\n");
101 // Lambda, dışarıdaki yerel değişkenleri kullanabilir; ancak bu değişkenler
102 // "effectively final" (etkin olarak değişmez) olmalıdır.
103 String onek = ">> "; // değiştirilmiyor -> effectively final
104 calisanlar.forEach(c -> System.out.println(onek + c.isim));
105 }
106
107 /** Lambda'nın hedefi olacak fonksiyonel arayüz (tek soyut metot). */
108 @FunctionalInterface
109 interface Hesaplama {
110 int hesapla(int a, int b);
111 }
112
113 /** Gerçek hayat domain sınıfı: Çalışan. */
114 static class Calisan {
115 String isim;
116 String departman;
117 double maas;
118
119 Calisan(String isim, String departman, double maas) {
120 this.isim = isim;
121 this.departman = departman;
122 this.maas = maas;
123 }
124
125 @Override
126 public String toString() {
127 return isim + " (" + departman + ", " + maas + " TL)";
128 }
129 }
130}MethodReferences
çalıştırılabilir1import java.util.Arrays;
2import java.util.Comparator;
3import java.util.List;
4import java.util.function.BiFunction;
5import java.util.function.Function;
6import java.util.function.Supplier;
7import java.util.stream.Collectors;
8
9/**
10 * ============================================================================
11 * METHOD REFERENCES (Metot Referansları) - Java 8
12 * ============================================================================
13 *
14 * NEDİR?
15 * Lambda ifadesinin daha da kısaltılmış halidir. Eğer bir lambda SADECE
16 * var olan bir metodu çağırıyorsa, lambda yerine doğrudan o metodun
17 * referansını verebiliriz. "::" operatörü kullanılır.
18 *
19 * s -> System.out.println(s) == System.out::println
20 *
21 * NEDEN GELDİ?
22 * Lambda zaten kısaydı ama "x -> Sinif.metot(x)" gibi yalnızca bir metoda
23 * delege eden lambdalar hâlâ gürültülüydü. Method reference bunu temizler;
24 * niyeti ("şu metodu kullan") açıkça gösterir, okunabilirliği artırır.
25 *
26 * DÖRT TÜRÜ VARDIR:
27 * 1) Static metot referansı -> Sinif::statikMetot
28 * 2) Belirli bir nesnenin metodu -> nesne::ornekMetot
29 * 3) Rastgele bir nesnenin örnek metodu-> Sinif::ornekMetot
30 * 4) Yapıcı (constructor) referansı -> Sinif::new
31 */
32public class MethodReferences {
33
34 public static void main(String[] args) {
35
36 List<String> kelimeler = Arrays.asList("elma", "Armut", "kiraz", "Banana");
37
38 System.out.println("=== TÜR 1: Static Metot Referansı (Sinif::statikMetot) ===\n");
39 // LAMBDA: s -> Integer.parseInt(s)
40 // REF : Integer::parseInt
41 List<String> sayilar = Arrays.asList("10", "25", "3", "47");
42 int toplam = sayilar.stream()
43 .mapToInt(Integer::parseInt) // static metot referansı
44 .sum();
45 System.out.println("Stringlerin toplami: " + toplam);
46
47 // Kendi static metodumuza referans
48 Function<String, String> selamla = MethodReferences::selamVer;
49 System.out.println(selamla.apply("Ahmet"));
50
51 System.out.println("\n=== TÜR 2: Belirli Nesnenin Metodu (nesne::metot) ===\n");
52 // LAMBDA: s -> System.out.println(s)
53 // REF : System.out::println (System.out belirli bir nesnedir)
54 kelimeler.forEach(System.out::println);
55
56 // Belirli bir nesneye bağlı
57 String onek = "Onek:";
58 Function<String, Boolean> baslarMi = onek::startsWith; // 'onek' nesnesinin metodu
59 System.out.println("'Onek:Test'.startsWith uygulamasi -> " + baslarMi.apply("Onek"));
60
61 System.out.println("\n=== TÜR 3: Rastgele Nesnenin Örnek Metodu (Sinif::metot) ===\n");
62 // LAMBDA: s -> s.toUpperCase() (her eleman için kendi metodu)
63 // REF : String::toUpperCase
64 List<String> buyukler = kelimeler.stream()
65 .map(String::toUpperCase) // her String'in kendi toUpperCase'i
66 .collect(Collectors.toList());
67 System.out.println("Buyuk harfli: " + buyukler);
68
69 // Sıralamada çok yaygın: String::compareToIgnoreCase
70 List<String> sirali = kelimeler.stream()
71 .sorted(String::compareToIgnoreCase)
72 .collect(Collectors.toList());
73 System.out.println("Buyuk/kucuk farketmeden sirali: " + sirali);
74
75 System.out.println("\n=== TÜR 4: Yapıcı (Constructor) Referansı (Sinif::new) ===\n");
76 // LAMBDA: ad -> new Kullanici(ad)
77 // REF : Kullanici::new
78 Function<String, Kullanici> kullaniciUret = Kullanici::new;
79 Kullanici k = kullaniciUret.apply("Zeynep");
80 System.out.println("Olusturulan kullanici: " + k);
81
82 // Stream ile toplu nesne üretimi
83 List<Kullanici> kullanicilar = Arrays.asList("Ali", "Veli", "Deli").stream()
84 .map(Kullanici::new) // her isim için yeni Kullanici
85 .collect(Collectors.toList());
86 System.out.println("Toplu uretim: " + kullanicilar);
87
88 // İki argümanlı constructor referansı (BiFunction)
89 BiFunction<String, Integer, Kullanici> yasliKullanici = Kullanici::new;
90 System.out.println("Yasli kullanici: " + yasliKullanici.apply("Hasan", 65));
91
92 // Supplier ile parametresiz constructor
93 Supplier<StringBuilder> sbUret = StringBuilder::new;
94 System.out.println("Bos StringBuilder uretildi, uzunluk: " + sbUret.get().length());
95
96 System.out.println("\n=== GERÇEK HAYAT: Çalışanları metot referanslarıyla işleme ===\n");
97 List<Calisan> calisanlar = Arrays.asList(
98 new Calisan("Mehmet", 42000),
99 new Calisan("Ayse", 55000),
100 new Calisan("Burak", 38000));
101
102 // Comparator.comparing + method reference
103 calisanlar.stream()
104 .sorted(Comparator.comparing(Calisan::getMaas)) // TÜR 3 referans
105 .map(Calisan::getIsim) // TÜR 3 referans
106 .forEach(System.out::println); // TÜR 2 referans
107 }
108
109 /** TÜR 1 örneği için static metot. */
110 static String selamVer(String isim) {
111 return "Merhaba " + isim + "!";
112 }
113
114 static class Kullanici {
115 String ad;
116 int yas;
117
118 Kullanici(String ad) {
119 this.ad = ad;
120 this.yas = 0;
121 }
122
123 Kullanici(String ad, int yas) {
124 this.ad = ad;
125 this.yas = yas;
126 }
127
128 @Override
129 public String toString() {
130 return ad + (yas > 0 ? "(" + yas + ")" : "");
131 }
132 }
133
134 static class Calisan {
135 private String isim;
136 private double maas;
137
138 Calisan(String isim, double maas) {
139 this.isim = isim;
140 this.maas = maas;
141 }
142
143 String getIsim() { return isim; }
144 double getMaas() { return maas; }
145 }
146}NashornOrnekleri
çalıştırılabilir1import javax.script.Invocable;
2import javax.script.ScriptEngine;
3import javax.script.ScriptEngineManager;
4
5/**
6 * ============================================================================
7 * NASHORN JAVASCRIPT ENGINE - Java 8
8 * ============================================================================
9 *
10 * NEDİR?
11 * Nashorn, Java 8 ile gelen, JVM üzerinde JavaScript kodu çalıştıran yüksek
12 * performanslı bir motordur. Java'dan JavaScript çağırabilir, JavaScript'ten
13 * Java nesnelerine erişebilirsin. javax.script (JSR-223) API'si üzerinden
14 * kullanılır.
15 *
16 * NEDEN GELDİ?
17 * Java 6'daki eski "Rhino" JavaScript motoru yavaş ve eskimişti. Nashorn,
18 * modern invokedynamic bytecode'unu kullanarak çok daha hızlı çalışır.
19 * Uygulamalara gömülü (embedded) scriptleme yeteneği kazandırmak için geldi:
20 * kullanıcıların iş kurallarını JavaScript ile tanımlaması, dinamik
21 * yapılandırma, kural motorları gibi senaryolar.
22 *
23 * NE İŞE YARAR: Java uygulamasını yeniden derlemeden dinamik script
24 * çalıştırma; kural motorları; şablon işleme; komut satırı (jjs aracı).
25 *
26 * ÖNEMLİ NOT (Geleceği):
27 * Nashorn, Java 11'de DEPRECATED (kullanımdan kaldırılması planlandı)
28 * edildi ve Java 15'te TAMAMEN KALDIRILDI. Bu yüzden modern projelerde
29 * GraalVM JavaScript gibi alternatifler tercih edilir. Bu örnek tarihsel
30 * ve Java 8 bağlamında öğretici amaçlıdır.
31 *
32 * DİKKAT: getEngineByName("nashorn") Java 8-14 arasında çalışır. Daha yeni
33 * JDK'larda engine null dönebilir; kod bu durumu nazikçe ele alır.
34 */
35public class NashornOrnekleri {
36
37 public static void main(String[] args) throws Exception {
38
39 ScriptEngineManager manager = new ScriptEngineManager();
40 ScriptEngine motor = manager.getEngineByName("nashorn");
41
42 if (motor == null) {
43 System.out.println("Nashorn motoru bu JDK surumunde mevcut DEGIL.");
44 System.out.println("(Nashorn Java 15'te kaldirildi. Java 8-14 ile calistirin.)");
45 return;
46 }
47
48 System.out.println("=== 1. Basit JavaScript çalıştırma ===\n");
49 motor.eval("print('JavaScript icinden merhaba!')");
50 Object sonuc = motor.eval("10 + 20 * 2");
51 System.out.println("JS ifadesinin sonucu: " + sonuc);
52
53 System.out.println("\n=== 2. Java'dan JS'e değişken geçirme ===\n");
54 motor.put("isim", "Ahmet");
55 motor.put("yas", 30);
56 motor.eval("print('Ad: ' + isim + ', Yas: ' + yas)");
57
58 System.out.println("\n=== 3. JS fonksiyonu tanımlayıp Java'dan çağırma ===\n");
59 motor.eval("function topla(a, b) { return a + b; }");
60 Invocable cagrilabilir = (Invocable) motor;
61 Object toplam = cagrilabilir.invokeFunction("topla", 15, 27);
62 System.out.println("JS topla(15, 27) = " + toplam);
63
64 System.out.println("\n=== 4. GERÇEK HAYAT: Dinamik iş kuralı (kural motoru) ===\n");
65 // Senaryo: Indirim kurali JavaScript ile tanimlanir; Java kodu
66 // yeniden derlenmeden kural degistirilebilir.
67 String indirimKurali =
68 "function indirim(tutar) {" +
69 " if (tutar > 1000) return tutar * 0.85;" + // %15 indirim
70 " else if (tutar > 500) return tutar * 0.95;" + // %5 indirim
71 " else return tutar;" +
72 "}";
73 motor.eval(indirimKurali);
74
75 double[] sepetler = {300, 700, 1500};
76 for (double sepet : sepetler) {
77 Object indirimli = cagrilabilir.invokeFunction("indirim", sepet);
78 System.out.printf("Sepet %.0f TL -> indirimli %.2f TL%n", sepet,
79 ((Number) indirimli).doubleValue());
80 }
81
82 System.out.println("\n=== 5. JS icinden Java sınıfına erişim ===\n");
83 // Nashorn, Java.type ile Java siniflarini kullanabilir
84 motor.eval(
85 "var ArrayList = Java.type('java.util.ArrayList');" +
86 "var liste = new ArrayList();" +
87 "liste.add('Elma'); liste.add('Armut');" +
88 "print('JS icinde olusturulan Java listesi: ' + liste);");
89 }
90}OptionalOrnekleri
çalıştırılabilir1import java.util.Arrays;
2import java.util.List;
3import java.util.Optional;
4
5/**
6 * ============================================================================
7 * OPTIONAL SINIFI - Java 8
8 * ============================================================================
9 *
10 * NEDİR?
11 * Optional<T>, "bir değer olabilir VEYA olmayabilir" durumunu temsil eden
12 * bir KAPSAYICIDIR (container). İçinde ya bir değer vardır ya da boştur.
13 * Amaç: null yerine, "değer yok" durumunu TİP SEVİYESİNDE açıkça belirtmek.
14 *
15 * NEDEN GELDİ? (Hangi problemi çözdü?)
16 * NullPointerException (NPE), Java'nın en sık görülen hatasıdır. Bir metot
17 * null döndürdüğünde, çağıran taraf bunu kontrol etmeyi unutursa program
18 * çöker. Tony Hoare null'ı "milyar dolarlık hata" diye adlandırmıştır.
19 * Optional, bir metodun "değer döndürmeyebilirim" demesini imza seviyesinde
20 * zorunlu kılar; böylece derleme zamanında dikkatli olmaya iter.
21 *
22 * NE İŞE YARAR: NPE riskini azaltır, kodun niyetini netleştirir, varsayılan
23 * değer / alternatif akış yönetimini kolaylaştırır.
24 *
25 * DİKKAT: Optional alan (field) olarak veya metot parametresi olarak
26 * kullanılması TAVSİYE EDİLMEZ. Esasen DÖNÜŞ TİPİ olarak tasarlanmıştır.
27 */
28public class OptionalOrnekleri {
29
30 static List<Kullanici> kullanicilar = Arrays.asList(
31 new Kullanici(1, "Ahmet", "ahmet@mail.com"),
32 new Kullanici(2, "Zeynep", null), // e-postası yok
33 new Kullanici(3, "Mehmet", "mehmet@mail.com"));
34
35 public static void main(String[] args) {
36
37 System.out.println("=== 1. ESKİ YÖNTEM: null kontrolü ===\n");
38 // ESKİ YÖNTEM: metot null döndürür, çağıran null kontrolü yapmak zorunda
39 Kullanici k = kullaniciBulEski(2);
40 if (k != null) { // unutulursa -> NPE
41 if (k.email != null) { // iç içe null kontrolleri
42 System.out.println("Email: " + k.email.toUpperCase());
43 } else {
44 System.out.println("Email yok (eski yontem)");
45 }
46 }
47
48 System.out.println("\n=== 2. YENİ YÖNTEM: Optional ile ===\n");
49 Optional<Kullanici> opt = kullaniciBul(2);
50 // isPresent / get (eski tarz, tavsiye edilmez ama mümkün)
51 if (opt.isPresent()) {
52 System.out.println("Bulundu: " + opt.get().isim);
53 }
54
55 System.out.println("\n=== 3. ifPresent : Değer varsa çalıştır ===\n");
56 kullaniciBul(1).ifPresent(u -> System.out.println("ifPresent -> " + u.isim));
57 kullaniciBul(99).ifPresent(u -> System.out.println("Bu satir CALISMAZ"));
58 System.out.println("99 numarali kullanici icin ifPresent calismadi (deger yok).");
59
60 System.out.println("\n=== 4. orElse / orElseGet / orElseThrow ===\n");
61 // orElse: değer yoksa varsayılan döndür
62 Kullanici varsayilan = kullaniciBul(99)
63 .orElse(new Kullanici(0, "Misafir", "yok@mail.com"));
64 System.out.println("orElse -> " + varsayilan.isim);
65
66 // orElseGet: varsayılanı LAZY üret (yalnızca gerekirse hesaplanır)
67 Kullanici lazy = kullaniciBul(99)
68 .orElseGet(() -> {
69 System.out.println(" (pahali varsayilan uretiliyor...)");
70 return new Kullanici(0, "Uretildi", null);
71 });
72 System.out.println("orElseGet -> " + lazy.isim);
73
74 // orElseThrow: değer yoksa istisna fırlat
75 try {
76 kullaniciBul(99).orElseThrow(() ->
77 new RuntimeException("Kullanici bulunamadi!"));
78 } catch (RuntimeException e) {
79 System.out.println("orElseThrow -> " + e.getMessage());
80 }
81
82 System.out.println("\n=== 5. map / flatMap : Zincirleme dönüşüm ===\n");
83 // E-postayı güvenle büyük harfe çevir; yoksa varsayılan yaz
84 String email = kullaniciBul(1)
85 .map(u -> u.email) // Optional<String>
86 .map(String::toUpperCase) // değer varsa dönüştür
87 .orElse("EMAIL YOK");
88 System.out.println("Kullanici 1 email: " + email);
89
90 // E-postası olmayan kullanıcı (Zeynep) -> zincir güvenle "EMAIL YOK"
91 String email2 = kullaniciBul(2)
92 .map(u -> u.email)
93 .map(String::toUpperCase)
94 .orElse("EMAIL YOK");
95 System.out.println("Kullanici 2 email: " + email2 + " (null guvenle ele alindi)");
96
97 System.out.println("\n=== 6. filter ile koşullu Optional ===\n");
98 // Sadece mail.com uzantılı e-postaları kabul et
99 String gecerli = kullaniciBul(3)
100 .map(u -> u.email)
101 .filter(e -> e != null && e.endsWith("mail.com"))
102 .orElse("GECERSIZ");
103 System.out.println("Gecerli email kontrolu: " + gecerli);
104
105 System.out.println("\n=== 7. Optional Oluşturma Yöntemleri ===\n");
106 Optional<String> dolu = Optional.of("deger"); // null OLAMAZ
107 Optional<String> bos = Optional.empty(); // bilerek boş
108 Optional<String> belkiNull = Optional.ofNullable(null);// null olabilir
109 System.out.println("of() -> " + dolu);
110 System.out.println("empty() -> " + bos);
111 System.out.println("ofNullable() -> " + belkiNull);
112
113 System.out.println("\n=== 8. GERÇEK HAYAT: Banka hesap bakiyesi ===\n");
114 // Hesap bulunamazsa 0 bakiye varsay, varsa bakiyeyi formatla
115 double bakiye = hesapBul("TR0001")
116 .map(h -> h.bakiye)
117 .orElse(0.0);
118 System.out.printf("TR0001 bakiye: %.2f TL%n", bakiye);
119
120 double bakiye2 = hesapBul("YOK")
121 .map(h -> h.bakiye)
122 .orElse(0.0);
123 System.out.printf("YOK bakiye: %.2f TL (hesap yok, guvenli varsayilan)%n", bakiye2);
124 }
125
126 /** ESKİ tarz: null döndürebilen metot (riskli). */
127 static Kullanici kullaniciBulEski(int id) {
128 for (Kullanici u : kullanicilar) {
129 if (u.id == id) return u;
130 }
131 return null; // çağıran null kontrolü yapmazsa NPE riski
132 }
133
134 /** YENİ tarz: Optional döndüren metot (güvenli, niyet açık). */
135 static Optional<Kullanici> kullaniciBul(int id) {
136 return kullanicilar.stream()
137 .filter(u -> u.id == id)
138 .findFirst(); // Stream zaten Optional döndürür
139 }
140
141 static Optional<Hesap> hesapBul(String iban) {
142 if (iban.equals("TR0001")) {
143 return Optional.of(new Hesap("TR0001", 12500.75));
144 }
145 return Optional.empty();
146 }
147
148 static class Kullanici {
149 int id;
150 String isim;
151 String email; // null olabilir
152
153 Kullanici(int id, String isim, String email) {
154 this.id = id;
155 this.isim = isim;
156 this.email = email;
157 }
158 }
159
160 static class Hesap {
161 String iban;
162 double bakiye;
163
164 Hesap(String iban, double bakiye) {
165 this.iban = iban;
166 this.bakiye = bakiye;
167 }
168 }
169}StreamApiOrnekleri
çalıştırılabilir1import java.util.ArrayList;
2import java.util.Arrays;
3import java.util.IntSummaryStatistics;
4import java.util.List;
5import java.util.Optional;
6import java.util.stream.Collectors;
7import java.util.stream.IntStream;
8import java.util.stream.Stream;
9
10/**
11 * ============================================================================
12 * STREAM API - Java 8
13 * ============================================================================
14 *
15 * NEDİR?
16 * Koleksiyonlar (List, Set vb.) üzerinde DEKLARATİF (ne istediğini söyle,
17 * nasıl yapılacağını değil) tarzda işlem yapmayı sağlayan bir API'dir.
18 * Bir "veri akışı" boru hattı kurarsın: kaynak -> ara işlemler -> sonlandırıcı.
19 *
20 * Yapısı:
21 * kaynak.stream()
22 * .filter(...) // ara işlem (lazy)
23 * .map(...) // ara işlem (lazy)
24 * .collect(...) // sonlandırıcı işlem (terminal) -> akışı tetikler
25 *
26 * NEDEN GELDİ? (Hangi problemi çözdü?)
27 * Eskiden koleksiyon işlemek için elle for döngüleri yazıyorduk. Filtrele +
28 * dönüştür + topla gibi işlemler iç içe döngüler ve geçici listelerle dolu,
29 * hata yapmaya açık, okunması zor kodlar üretiyordu. Stream API bu işlemleri
30 * tek bir akıcı (fluent) zincire indirger.
31 *
32 * ÖNEMLİ KAVRAMLAR:
33 * - LAZY (tembel): Ara işlemler, terminal işlem çağrılana kadar çalışmaz.
34 * - Stream tek kullanımlıktır: Tüketildikten sonra tekrar kullanılamaz.
35 * - PARALEL stream: .parallelStream() ile işlemler çoklu çekirdekte dağıtılır.
36 *
37 * NE İŞE YARAR / NEREDE KOLAYLIK: Filtreleme, dönüştürme, gruplama, toplama,
38 * istatistik çıkarma, raporlama -> e-ticaret, banka, log analizi vb.
39 */
40public class StreamApiOrnekleri {
41
42 public static void main(String[] args) {
43
44 List<Urun> urunler = Arrays.asList(
45 new Urun("Telefon", "Elektronik", 15000, 12),
46 new Urun("Laptop", "Elektronik", 32000, 5),
47 new Urun("Kulaklik", "Elektronik", 800, 40),
48 new Urun("Kitap", "Yayin", 120, 200),
49 new Urun("Defter", "Yayin", 35, 500),
50 new Urun("Kahve", "Gida", 250, 80));
51
52 System.out.println("=== 1. ESKİ YÖNTEM vs filter+map+collect ===\n");
53
54 // ESKİ YÖNTEM (Java 7): elle döngü + geçici liste
55 List<String> pahaliElektronikEski = new ArrayList<>();
56 for (Urun u : urunler) {
57 if (u.kategori.equals("Elektronik") && u.fiyat > 1000) {
58 pahaliElektronikEski.add(u.ad.toUpperCase());
59 }
60 }
61 System.out.println("Eski yontem : " + pahaliElektronikEski);
62
63 // YENİ YÖNTEM (Java 8 Stream): okunabilir, deklaratif
64 List<String> pahaliElektronikYeni = urunler.stream()
65 .filter(u -> u.kategori.equals("Elektronik"))
66 .filter(u -> u.fiyat > 1000)
67 .map(u -> u.ad.toUpperCase())
68 .collect(Collectors.toList());
69 System.out.println("Stream API : " + pahaliElektronikYeni);
70
71 System.out.println("\n=== 2. map : Dönüştürme ===\n");
72 List<Double> kdvliFiyatlar = urunler.stream()
73 .map(u -> u.fiyat * 1.20)
74 .collect(Collectors.toList());
75 System.out.println("KDV'li fiyatlar: " + kdvliFiyatlar);
76
77 System.out.println("\n=== 3. reduce : İndirgeme (tek değere düşürme) ===\n");
78 // Tüm stoğun toplam değeri (fiyat * adet)
79 double toplamStokDegeri = urunler.stream()
80 .map(u -> u.fiyat * u.stokAdedi)
81 .reduce(0.0, Double::sum); // başlangıç 0, ardışık topla
82 System.out.println("Toplam stok degeri: " + toplamStokDegeri + " TL");
83
84 // reduce ile en pahalı ürünü bulma
85 Optional<Urun> enPahali = urunler.stream()
86 .reduce((u1, u2) -> u1.fiyat > u2.fiyat ? u1 : u2);
87 enPahali.ifPresent(u -> System.out.println("En pahali urun: " + u.ad));
88
89 System.out.println("\n=== 4. flatMap : İç içe yapıları düzleştirme ===\n");
90 // Her siparişin birden fazla ürünü var; tüm ürünleri tek listede topla
91 List<Siparis> siparisler = Arrays.asList(
92 new Siparis("S1", Arrays.asList("Telefon", "Kulaklik")),
93 new Siparis("S2", Arrays.asList("Laptop")),
94 new Siparis("S3", Arrays.asList("Kitap", "Defter", "Kahve")));
95
96 List<String> tumUrunler = siparisler.stream()
97 .flatMap(s -> s.urunler.stream()) // List<List<String>> -> Stream<String>
98 .collect(Collectors.toList());
99 System.out.println("Tum siparis kalemleri: " + tumUrunler);
100
101 // Benzersiz ürünler
102 List<String> benzersiz = siparisler.stream()
103 .flatMap(s -> s.urunler.stream())
104 .distinct()
105 .sorted()
106 .collect(Collectors.toList());
107 System.out.println("Benzersiz (sirali) : " + benzersiz);
108
109 System.out.println("\n=== 5. Sayısal Stream'ler ve İstatistik ===\n");
110 IntSummaryStatistics istatistik = urunler.stream()
111 .mapToInt(u -> u.stokAdedi)
112 .summaryStatistics();
113 System.out.println("Toplam stok adedi : " + istatistik.getSum());
114 System.out.println("Ortalama stok : " + istatistik.getAverage());
115 System.out.println("En cok stok : " + istatistik.getMax());
116 System.out.println("En az stok : " + istatistik.getMin());
117
118 System.out.println("\n=== 6. limit / skip / sorted / count ===\n");
119 // En pahalı 3 ürün
120 System.out.println("En pahali 3 urun:");
121 urunler.stream()
122 .sorted((a, b) -> Double.compare(b.fiyat, a.fiyat))
123 .limit(3)
124 .forEach(u -> System.out.println(" " + u.ad + " - " + u.fiyat));
125
126 long elektronikSayisi = urunler.stream()
127 .filter(u -> u.kategori.equals("Elektronik"))
128 .count();
129 System.out.println("Elektronik urun sayisi: " + elektronikSayisi);
130
131 System.out.println("\n=== 7. anyMatch / allMatch / noneMatch ===\n");
132 boolean herseyStokta = urunler.stream().allMatch(u -> u.stokAdedi > 0);
133 boolean pahaliVar = urunler.stream().anyMatch(u -> u.fiyat > 30000);
134 boolean bedavaYok = urunler.stream().noneMatch(u -> u.fiyat == 0);
135 System.out.println("Hepsi stokta mi? " + herseyStokta);
136 System.out.println("30000 ustu var mi? " + pahaliVar);
137 System.out.println("Bedava urun yok mu? " + bedavaYok);
138
139 System.out.println("\n=== 8. Stream.iterate / generate / IntStream.range ===\n");
140 // İlk 5 çift sayı
141 List<Integer> ciftler = Stream.iterate(0, n -> n + 2)
142 .limit(5)
143 .collect(Collectors.toList());
144 System.out.println("Ilk 5 cift sayi: " + ciftler);
145
146 // IntStream.range ile toplam
147 int kareToplam = IntStream.rangeClosed(1, 5)
148 .map(n -> n * n)
149 .sum();
150 System.out.println("1..5 karelerinin toplami: " + kareToplam);
151
152 System.out.println("\n=== 9. PARALEL STREAM (çoklu çekirdek) ===\n");
153 // Büyük veri için işlem çekirdeklere dağıtılır. DİKKAT: küçük veride
154 // ek yük (overhead) nedeniyle daha yavaş olabilir.
155 long buyukToplam = IntStream.rangeClosed(1, 1_000_000)
156 .parallel()
157 .mapToLong(i -> (long) i)
158 .sum();
159 System.out.println("1..1.000.000 paralel toplam: " + buyukToplam);
160 System.out.println("Kullanilan cekirdek sayisi : "
161 + Runtime.getRuntime().availableProcessors());
162 }
163
164 static class Urun {
165 String ad, kategori;
166 double fiyat;
167 int stokAdedi;
168
169 Urun(String ad, String kategori, double fiyat, int stokAdedi) {
170 this.ad = ad;
171 this.kategori = kategori;
172 this.fiyat = fiyat;
173 this.stokAdedi = stokAdedi;
174 }
175
176 @Override
177 public String toString() {
178 return ad + " [" + kategori + "] " + fiyat + " TL x" + stokAdedi;
179 }
180 }
181
182 static class Siparis {
183 String no;
184 List<String> urunler;
185
186 Siparis(String no, List<String> urunler) {
187 this.no = no;
188 this.urunler = urunler;
189 }
190 }
191}StringJoinerOrnekleri
çalıştırılabilir1import java.util.Arrays;
2import java.util.List;
3import java.util.StringJoiner;
4import java.util.stream.Collectors;
5
6/**
7 * ============================================================================
8 * StringJoiner ve String.join - Java 8
9 * ============================================================================
10 *
11 * NEDİR?
12 * - String.join(...) : Statik bir yardımcı metot. Birden fazla parçayı
13 * belirli bir ayırıcıyla (delimiter) birleştirir.
14 * - StringJoiner : Ayırıcı (delimiter), önek (prefix) ve sonek (suffix)
15 * ile metin parçalarını biriktirip birleştiren sınıf.
16 *
17 * NEDEN GELDİ? (Hangi problemi çözdü?)
18 * Bir listeyi "a, b, c" gibi virgülle birleştirmek çok yaygın bir ihtiyaçtı
19 * ama Java'da standart bir yolu yoktu. Geliştiriciler genelde döngü içinde
20 * StringBuilder kullanıp "SON elemana virgül koymama" mantığını elle
21 * yazıyordu. Bu, tekrar eden ve hata yapmaya açık (sondaki fazladan virgül
22 * gibi) bir koddu. Java 8 bunu standartlaştırdı.
23 *
24 * NE İŞE YARAR: CSV satırı üretme, SQL IN listesi, log mesajları, URL query
25 * parametreleri, raporlarda "etiket listesi" gibi yerlerde.
26 */
27public class StringJoinerOrnekleri {
28
29 public static void main(String[] args) {
30
31 List<String> sehirler = Arrays.asList("Istanbul", "Ankara", "Izmir", "Bursa");
32
33 System.out.println("=== 1. ESKİ YÖNTEM: StringBuilder + manuel ayırıcı ===\n");
34 // ESKİ YÖNTEM: son virgülü engellemek için ekstra mantık gerekir
35 StringBuilder sb = new StringBuilder();
36 for (int i = 0; i < sehirler.size(); i++) {
37 sb.append(sehirler.get(i));
38 if (i < sehirler.size() - 1) { // son elemana virgül KOYMA kontrolü
39 sb.append(", ");
40 }
41 }
42 System.out.println("StringBuilder ile: " + sb.toString());
43
44 System.out.println("\n=== 2. YENİ YÖNTEM: String.join ===\n");
45 // YENİ YÖNTEM: tek satır, hata riski yok
46 String birlesik = String.join(", ", sehirler);
47 System.out.println("String.join ile : " + birlesik);
48 // Varargs ile de calisir
49 System.out.println("Varargs ile : " + String.join(" - ", "A", "B", "C"));
50
51 System.out.println("\n=== 3. StringJoiner: ayırıcı + önek + sonek ===\n");
52 StringJoiner sj = new StringJoiner(", ", "[", "]");
53 sehirler.forEach(sj::add);
54 System.out.println("StringJoiner: " + sj.toString());
55
56 System.out.println("\n=== 4. Boş durumda 'emptyValue' ===\n");
57 StringJoiner bos = new StringJoiner(", ", "{", "}");
58 bos.setEmptyValue("(liste bos)"); // hic add edilmezse bu yazi cikar
59 System.out.println("Bos joiner: " + bos.toString());
60
61 System.out.println("\n=== 5. Stream + Collectors.joining (en pratiği) ===\n");
62 List<Calisan> calisanlar = Arrays.asList(
63 new Calisan("Ahmet", "Yazilim"),
64 new Calisan("Zeynep", "Pazarlama"),
65 new Calisan("Mehmet", "Finans"));
66
67 // İsimleri tek satırda birleştir
68 String isimSatiri = calisanlar.stream()
69 .map(c -> c.isim)
70 .collect(Collectors.joining(", ", "Calisanlar: ", "."));
71 System.out.println(isimSatiri);
72
73 System.out.println("\n=== 6. GERÇEK HAYAT: CSV satırı üretme ===\n");
74 for (Calisan c : calisanlar) {
75 String csvSatir = new StringJoiner(";")
76 .add(c.isim)
77 .add(c.departman)
78 .toString();
79 System.out.println(csvSatir);
80 }
81
82 System.out.println("\n=== 7. GERÇEK HAYAT: SQL IN listesi ===\n");
83 List<Integer> idler = Arrays.asList(101, 102, 103, 205);
84 String inListesi = idler.stream()
85 .map(String::valueOf)
86 .collect(Collectors.joining(", ", "WHERE id IN (", ")"));
87 System.out.println(inListesi);
88
89 System.out.println("\n=== 8. GERÇEK HAYAT: URL query string ===\n");
90 StringJoiner query = new StringJoiner("&", "?", "");
91 query.add("kategori=elektronik");
92 query.add("siralama=fiyat");
93 query.add("sayfa=1");
94 System.out.println("https://magaza.com/urunler" + query);
95 }
96
97 static class Calisan {
98 String isim, departman;
99
100 Calisan(String isim, String departman) {
101 this.isim = isim;
102 this.departman = departman;
103 }
104 }
105}YeniTarihSaatApi
çalıştırılabilir1import java.time.DayOfWeek;
2import java.time.Duration;
3import java.time.Instant;
4import java.time.LocalDate;
5import java.time.LocalDateTime;
6import java.time.LocalTime;
7import java.time.Month;
8import java.time.Period;
9import java.time.ZoneId;
10import java.time.ZonedDateTime;
11import java.time.format.DateTimeFormatter;
12import java.time.temporal.ChronoUnit;
13import java.util.Calendar;
14import java.util.Date;
15
16/**
17 * ============================================================================
18 * YENİ TARİH/SAAT API (java.time) - Java 8
19 * ============================================================================
20 *
21 * NEDİR?
22 * java.time paketi; LocalDate, LocalTime, LocalDateTime, ZonedDateTime,
23 * Duration, Period, Instant gibi MODERN tarih/saat sınıfları getirir.
24 * (JSR-310, Joda-Time kütüphanesinden ilham alınarak tasarlandı.)
25 *
26 * NEDEN GELDİ? (Eski Date/Calendar'ın sorunları neydi?)
27 * 1) DEĞİŞTİRİLEBİLİR (mutable): java.util.Date nesnesi sonradan değişebilir
28 * -> çoklu iş parçacığında (thread) güvensiz, beklenmedik hatalar.
29 * 2) KAFA KARIŞTIRAN API: Calendar'da AY 0'DAN BAŞLAR (Ocak = 0!). Yıl
30 * 1900 tabanlıydı. Çok sayıda hataya yol açtı.
31 * 3) Zaman dilimi (timezone) yönetimi zayıf ve hataya açıktı.
32 * 4) Tarih aritmetiği (3 gün ekle, iki tarih farkı) çok zahmetliydi.
33 *
34 * java.time bunların hepsini çözer: DEĞİŞMEZ (immutable), thread-safe,
35 * akıcı (fluent) ve insan-okunabilir API.
36 *
37 * NE İŞE YARAR: Doğum günü hesaplama, fatura kesim tarihleri, rezervasyon
38 * süreleri, zaman dilimi dönüşümleri, yaş hesaplama vb.
39 */
40public class YeniTarihSaatApi {
41
42 public static void main(String[] args) {
43
44 System.out.println("=== 1. ESKİ Date/Calendar SORUNLARI ===\n");
45 // ESKİ YÖNTEM: 24 Haziran 2026 olusturmak istiyoruz
46 Calendar cal = Calendar.getInstance();
47 cal.set(2026, 5, 24); // DİKKAT: ay 5 = HAZIRAN (0'dan basliyor!) -> kafa karistirici
48 Date eskiTarih = cal.getTime();
49 System.out.println("Eski Calendar (ay 0-tabanli!): " + eskiTarih);
50 System.out.println(" -> 'cal.set(2026, 5, 24)' aslinda HAZIRAN demek, MAYIS degil!");
51
52 System.out.println("\n=== 2. YENİ YÖNTEM: LocalDate ===\n");
53 // YENİ YÖNTEM: ay numaralari INSAN MANTIGIYLA (Haziran = 6)
54 LocalDate bugun = LocalDate.of(2026, 6, 24);
55 System.out.println("LocalDate.of(2026, 6, 24): " + bugun + " (Haziran = 6, net!)");
56 System.out.println("Su anki tarih (now) : " + LocalDate.now());
57 System.out.println("Ay : " + bugun.getMonth() + " (" + bugun.getMonthValue() + ")");
58 System.out.println("Haftanin gunu: " + bugun.getDayOfWeek());
59 System.out.println("Yilin kacinci gunu: " + bugun.getDayOfYear());
60 System.out.println("Arti gecmis mi (leap year)? " + bugun.isLeapYear());
61
62 System.out.println("\n=== 3. Tarih Aritmetiği (immutable - yeni nesne döner) ===\n");
63 LocalDate gelecek = bugun.plusDays(10).plusMonths(2).minusYears(1);
64 System.out.println("bugun + 10 gun + 2 ay - 1 yil = " + gelecek);
65 System.out.println("Orijinal degismedi (immutable): " + bugun);
66
67 System.out.println("\n=== 4. LocalTime ve LocalDateTime ===\n");
68 LocalTime saat = LocalTime.of(14, 30, 0);
69 System.out.println("Saat: " + saat);
70 LocalDateTime randevu = LocalDateTime.of(2026, Month.JULY, 1, 9, 15);
71 System.out.println("Randevu: " + randevu);
72
73 System.out.println("\n=== 5. Period : İki TARİH arası fark (yıl/ay/gün) ===\n");
74 LocalDate dogumGunu = LocalDate.of(1990, 3, 15);
75 Period yas = Period.between(dogumGunu, bugun);
76 System.out.printf("Yas: %d yil, %d ay, %d gun%n",
77 yas.getYears(), yas.getMonths(), yas.getDays());
78 long toplamGun = ChronoUnit.DAYS.between(dogumGunu, bugun);
79 System.out.println("Dogumdan bu yana toplam gun: " + toplamGun);
80
81 System.out.println("\n=== 6. Duration : İki ZAMAN arası fark (saat/dakika/sn) ===\n");
82 LocalTime baslangic = LocalTime.of(9, 0);
83 LocalTime bitis = LocalTime.of(17, 30);
84 Duration mesai = Duration.between(baslangic, bitis);
85 System.out.println("Mesai suresi: " + mesai.toHours() + " saat "
86 + (mesai.toMinutes() % 60) + " dakika");
87
88 System.out.println("\n=== 7. ZonedDateTime : Zaman Dilimi Yönetimi ===\n");
89 ZonedDateTime istanbul = ZonedDateTime.now(ZoneId.of("Europe/Istanbul"));
90 ZonedDateTime newYork = istanbul.withZoneSameInstant(ZoneId.of("America/New_York"));
91 ZonedDateTime tokyo = istanbul.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
92 System.out.println("Istanbul: " + istanbul);
93 System.out.println("New York: " + newYork);
94 System.out.println("Tokyo : " + tokyo);
95
96 System.out.println("\n=== 8. Formatlama (DateTimeFormatter) ===\n");
97 DateTimeFormatter trFormat = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm");
98 System.out.println("Formatli: " + randevu.format(trFormat));
99 // Metinden tarihe çevirme (parse)
100 LocalDate parsed = LocalDate.parse("2026-12-31");
101 System.out.println("Parse edildi: " + parsed);
102
103 System.out.println("\n=== 9. Instant : Makine zamanı (epoch) ===\n");
104 Instant simdi = Instant.now();
105 System.out.println("Instant (UTC): " + simdi);
106 System.out.println("Epoch saniye : " + simdi.getEpochSecond());
107
108 System.out.println("\n=== 10. GERÇEK HAYAT: Fatura kesim ve vade ===\n");
109 LocalDate faturaTarihi = LocalDate.of(2026, 6, 1);
110 LocalDate sonOdeme = faturaTarihi.plusDays(30);
111 System.out.println("Fatura tarihi : " + faturaTarihi);
112 System.out.println("Son odeme : " + sonOdeme);
113 long kalanGun = ChronoUnit.DAYS.between(bugun, sonOdeme);
114 System.out.println("Bugune gore kalan gun: " + kalanGun);
115
116 // Bir sonraki Pazartesi (TemporalAdjuster mantığı)
117 LocalDate sonrakiPazartesi = bugun;
118 do {
119 sonrakiPazartesi = sonrakiPazartesi.plusDays(1);
120 } while (sonrakiPazartesi.getDayOfWeek() != DayOfWeek.MONDAY);
121 System.out.println("Bir sonraki Pazartesi: " + sonrakiPazartesi);
122 }
123}