Java 21 OCP Chapter 8: Lambda ve Fonksiyonel Interface
🔍 Java’da Lambda İfadeleri Nasıl Çalışır?
Java 21 OCP Chapter 8: Lambda ve Fonksiyonel Interface
🔍 Java’da Lambda İfadeleri Nasıl Çalışır?
Java’daki lambda ifadeleri, yalnızca tek bir abstract metoda sahip interfacelerle (Functional Interface) çalışır. Çünkü lambda ifadesi aslında o tek abstract metodun anonim bir implementasyonudur.
🟦 Lambda İfadesinin Temel Yapısı
Bir lambda ifadesi genel olarak şu formu izler:
parametre → gövde
Burada:
- a → parametre adıdır
- -> → parametre ile gövdeyi ayırır
- a.hop() → çalışacak kod bloğudur (body)
🟦 Örnekler
✔ 1) Tek parametre — tür belirtilmeden
a -> a.hop()
✔ 2) Parametre tipi belirtilmiş hâli
(String a) -> a.hop()
Parametre tipini yazarsanız parantez zorunludur.
✔ 3) Block Body Örneği
a -> { return a.hop(); }
🟦 Functional Interface Nedir?
Functional Interface, içerisinde tam olarak bir adet abstract method bulunan interfacetir. Lambda ifadeleri bu interface türleriyle çalışır.
Java bu interface’leri üç şekilde tanımlamamıza izin verir.
🟩 1) Tek abstract method yazarak (en temel tanım)
interface Flyer {
void fly();
}
Bu interface functional interface’tir çünkü içinde yalnızca bir abstract method vardır.
🟩 2) @FunctionalInterface Annotation’ı ile
Bu annotation zorunlu değildir ama derleyicinin kontrol yapmasını sağlar. Eğer ikinci bir abstract method eklersen, IDE hata verir.
@FunctionalInterface
interface Runner {
void run();
}
Avantaj: ✔ Yanlışlıkla ikinci abstract method eklemeyi engeller.
🟩 3) Default ve Static Method Eklemek Serbesttir
Functional interface olmayı bozmayan şeyler:
- default methodlar
- static methodlar
- private methodlar (Java 9+)
Çünkü functional interface’i belirleyen tek şey: ➡ Abstract method sayısının sadece 1 olmasıdır.
Bir functional interface’in içinde ekleyebileceğin bazı metodlar abstract sayılmaz ve bu nedenle functional interface özelliğini bozmaz.
Bunlar şunlardır:
toString()equals(Object o)hashCode()
✔ Neden bozmaz?
Çünkü bu üç metod Object sınıfından MİRAS gelir.
🟦 Java’da Method Reference Kullanmak
Lambda ifadelerinin daha da kısaltılmış hâlidir. Bir lambda ifadesi zaten var olan bir metodu doğrudan çağırıyorsa, o lambda yerine method reference kullanılabilir.
Method reference, lambdanın yaptığı işi adıyla gösterir:
ClassName::methodName
objectName::methodName
ClassName::new
Lambda → “nasıl yapılacağını” yazar Method reference → “hangi metodun yapılacağını” işaret eder
🟩 1) Static Method Reference
Bir sınıfın static metodunu referans gösterir.
Function<String, Integer> f = Integer::parseInt;
Lambda eşdeğeri:
s -> Integer.parseInt(s)
🟩 2) Instance Method Reference (belirli bir objeye bağlı)
Consumer<String> c = System.out::println;
Lambda eşdeğeri:
x -> System.out.println(x)
🟩 3) Instance Method Reference (sınıf üzerinden)
Parametre, metodun üzerinde çalışacağı nesnedir.
Function<String, Integer> f = String::length;
Lambda eşdeğeri:
s -> s.length()
🟩 4) Constructor Reference (new referansı)
Supplier<ArrayList> s = ArrayList::new;
Lambda eşdeğeri:
() -> new ArrayList()
Ayrıca parametre alan constructor’lar da referanslanabilir:
Function<Integer, ArrayList> f = ArrayList::new;
🟦 Java’da Built-in Functional Interface’lerle Çalışmak
Java, lambda ve method reference kullanabilmemiz için hazır (built-in) functional interface’ler sağlar. Bu sayede kendi interface’imizi tanımlamadan, doğrudan fonksiyonel kod yazabiliriz.
Bu interfaceler java.util.function paketinde bulunur.

🟩 1) Supplier — Bir şey üretir, parametre almaz
Parametre almaz → değer döndürür
Supplier<Double> random = Math::random;
System.out.println(random.get());
🟩 2) Consumer — Bir şey alır, geri döndürmez
Parametre alır → işlem yapar → void döner
Consumer<String> c = s -> System.out.println(s);
c.accept("Hello");
Method reference:
Consumer<String> c = System.out::println;
🟩 3) Function<T, R> — Bir değer alır, başka bir değer döndürür
T parametre → R dönüş tipi
Function<String, Integer> len = String::length;
System.out.println(len.apply("Java")); // 4
🟩 4) Predicate — Şart kontrol eder (true/false döner)
Predicate<Integer> isEven = n -> n % 2 == 0;
System.out.println(isEven.test(10)); // true
🟩 5) BiConsumer, BiFunction, BiPredicate
İki parametreyle çalışan versiyonlardır:
BiConsumer<String, Integer> print = (a, b) -> System.out.println(a + " = " + b);
print.accept("Age", 25);
🟩 1) UnaryOperator<T>
Bir tane parametre alır ve aynı tipte bir değer döndürür.
Function<T, T> ile tamamen aynı, sadece isim olarak daha anlamlıdır.
✔ Örnek
UnaryOperator<Integer> square = x -> x * x;
System.out.println(square.apply(5)); // 25
🟩 2) BinaryOperator<T>
İki parametre alır ve aynı tipte bir değer döndürür.
BiFunction<T, T, T> ile aynıdır; üç parametre tipi yerine tek bir T kullanır.
✔ Örnek
BinaryOperator<Integer> sum = (a, b) -> a + b;
System.out.println(sum.apply(3, 4)); // 7
🟦 Built-in Functional Interface → Lambda → Method Reference
Her biri üç şekilde kullanılabilir:
1) Lambda ile:
Function<String, Integer> f = s -> s.length();
2) Method reference ile:
Function<String, Integer> f = String::length;
3) Block lambda ile:
Function<String, Integer> f = s -> {
return s.length();
};
.
🟦 Functional Interfacelerde Convenience Methodlar
Functional interface’lerin çoğu, ana abstract metodun yanında işi kolaylaştıran ek yardımcı metodlar (convenience methods) içerir. Bu metodlar default veya static olarak tanımlanır ve functional interface’in davranışını zincirleme (compose), tersine çevirme (negate), birleştirme (and, or) gibi işlevler ekler.
Bu convenience metodlar functional interface olmalarını bozmaz, çünkü abstract metod sayısı hâlâ 1’dir.
🟩 1) Predicate — and(), or(), negate()
Predicate boolean döndürdüğü için Java sık kullanılan mantıksal kombinasyonları kolaylaştırmış default metodlara sahiptir:
Predicate<String> isShort = s -> s.length() < 5;
Predicate<String> startsWithA = s -> s.startsWith("A");
Predicate<String> combined = isShort.and(startsWithA);
Predicate<String> negated = isShort.negate();
🟦 5) Consumer — andThen()
Birden fazla işlem zincirlemek için:
Consumer<String> c1 = s -> System.out.println("Hello " + s);
Consumer<String> c2 = s -> System.out.println("Length: " + s.length());
Consumer<String> combined = c1.andThen(c2);
combined.accept("Java");
🟩 2) Function — andThen() ve compose()
Function<T, R> zincirleme (pipeline) mantığı için iki convenience method sunar:
✔ andThen() → önce bu, sonra şu
Function<Integer, Integer> times2 = x -> x * 2;
Function<Integer, Integer> plus3 = x -> x + 3;
Function<Integer, Integer> pipeline = times2.andThen(plus3);
pipeline.apply(5); // (5 * 2) + 3 = 13
✔ compose() → önce şu, sonra bu
Function<Integer, Integer> pipeline2 = times2.compose(plus3);
pipeline2.apply(5); // (5 + 3) * 2 = 16
🟦 Primitive Tipler için Functional Interfaces
🟩 1) BooleanSupplier
Bir değer üretir → boolean döner Parametre almaz.
BooleanSupplier isReady = () -> true;
System.out.println(isReady.getAsBoolean()); // true
2) Long Double ve Int için

🟦Lambdalarda değişkenlerle çalışmak
Java’da lambda ifadeleri kapsam (scope) kurallarına sıkı sıkıya bağlıdır.
🟦 Lambdalarda var Kullanımı
Java, lambda parametrelerinde **var** kullanımına izin verir.
Eğer lambda parametresi var ile tanımlanırsa:
Compiler, parametrenin tipini otomatik olarak functional interface’in generic tipinden çıkarır.
Yani var, lambdada türü saklamaz, sadece türün inference (çıkarım) yoluyla belirlenmesine izin verir.
🟩 ✔ Örnek — Type Inference (Tip Çıkarımı)
Function<String, Integer> f = (var s) -> s.length();
Burada:
- Functional interface →
Function<String, Integer> - Parametre tipi →
String var s→ compiler bunu String olarak yorumlar.
Dolayısıyla:
(var s) -> s.length()
ile
(String s) -> s.length()
tamamen aynıdır.
🟦 Lambda Body’de Local Variable Kullanma
Java’da lambda ifadeleri, tanımlandıkları metodun içindeki yerel değişkenlere (local variables) erişebilir. Ancak bu erişimin çok önemli bir kuralı vardır:
Lambda body, yalnızca “effectively final” local variable’lara erişebilir.
🟩 ✔ “Effectively Final” Ne Demek?
Bir değişken:
finalolarak işaretlenmişse veya- Değeri hiç değiştirilmemişse
→ effectively final sayılır.
🟦 ❌ Geçersiz (Invalid) — Parametreyi tekrar tanımlamak
Lambda parametresinin adını lambda body içinde yeniden tanımlayamazsın.
(a) -> {
int a = 10; // ❌ compile error: variable a is already defined
return a;
}
Sonraki konumuzda “Chapter 9| Collections ve Generic” konusunu ele alacağız.
Bana ulaşmak isterseniz;
***LinkedIn Github Instagram***

메타데이터
- post_id
- cce56dc0e6da
- slug
- java-21-ocp-chapter-8-lamba-ve-fonksiyonel-interface-cce56dc0e6da
- url
- https://medium.com/@ardaonur_yazilim/java-21-ocp-chapter-8-lamba-ve-fonksiyonel-interface-cce56dc0e6da
- canonical_url
- https://medium.com/@ardaonur_yazilim/java-21-ocp-chapter-8-lamba-ve-fonksiyonel-interface-cce56dc0e6da
- author_url
- https://medium.com/@ardaonur_yazilim
- status
- ok
- fetched_at
- 2026-07-09 13:13:48