4. Java 8'deki lambda fonksiyonları
4.1. Örnek-01 - İşlevsel arayüzler ve lambda fonksiyonları
![]() |
Aşağıdaki kodu ele alalım:
package dvp.java8.lambdas;
public class Exemple01 {
public static void main(String[] args) {
// anonim sınıflar
I1 ia1 = new I1() {
@Override
public void doSomething() {
System.out.println("ia1.doSomething");
}
};
I2 ia2 = new I2() {
@Override
public String getSomething(double value) {
return String.format("ia2.getSomething(%s)", value);
}
};
// lambda ifadeleri
I1 ib1 = () -> System.out.println("ib1.lambda");
I2 ib2 = (value) -> String.format("ib2.lambda(%s)", value);
I1 ib3 = () -> {
System.out.println("ib3.lambda");
};
I2 ib4 = (double value) -> {
return String.format("ib4.lambda(%s)", value);
};
// uygulama
ia1.doSomething();
System.out.println(ia2.getSomething(4.3));
ib1.doSomething();
System.out.println(ib2.getSomething(5.8));
ib3.doSomething();
System.out.println(ib4.getSomething(10.1));
}
}
@FunctionalInterface
interface I1 {
void doSomething();
}
@FunctionalInterface
interface I2 {
String getSomething(double value);
}
- 41-44. satırlar: I1 işlevsel arayüzünü tanımlar. İşlevsel arayüz, yalnızca bir yönteme sahip olan bir arayüzdür. Bu, 41. satırdaki isteğe bağlı [@FunctionalInterface] anotasyonunun varlığıyla bağlantılı değildir;
- 46-49. satırlar: ikinci bir işlevsel arayüz olan I2;
- satır 6-19: I1 ve I2 arayüzleri, lambda fonksiyonlarının ortaya çıkmasından önce en yaygın çözüm olan isimsiz sınıflarla uygulanmıştır;
- 21-29. satırlar: I1 ve I2 arayüzleri lambda fonksiyonlarıyla uygulanmıştır;
- 7-12. satırlar: I1 arayüzünün isimsiz bir sınıfla uygulanması. I arayüzünü isimsiz bir sınıfla uygulamak için kullanılan sözdizimi şöyledir:
burada m1, m2, ..., I arayüzü tarafından tanımlanan yöntemlerdir.
- 14-19. satırlar: I2 arayüzünün isimsiz bir sınıfla uygulanması;
- 22. satır: I1 arayüzünün bir lambda fonksiyonu ile uygulanması. Burada, fonksiyonel arayüzün tek bir yönteme sahip olmasından yararlanılır. Lambda fonksiyonu, bu tek M yöntemini uygular. Sözdizimi şöyledir:
T1, T2 ve Tn türleri, derleyici bunları bağlamdan çıkarabiliyorsa (tür çıkarım) atlanabilir.
- 22. satır: İmzası aşağıdaki gibi olan [I1.doSomething] yönteminin uygulaması:
void doSomething();
[doSomething], hiçbir parametre almayan ve sonuç döndürmeyen bir yöntemdir. Bu lambda uygulaması, 22. satırdaki gibi ya da 24-26. satırlardaki gibi yazılabilir; yani lambda fonksiyonunun kodunun etrafına küme parantezleri konulabilir. Bu kod, burada olduğu gibi tek bir komut içeriyorsa, bu küme parantezleri atlanabilir;
- 23. satır: [I1.getSomething] yönteminin uygulaması; imza:
String getSomething(double value);
[getSomething], [double] türünde bir parametre alır ve [String] türünde bir sonuç döndürür. Lambda uygulaması, 23. satırdakiyle veya 27-29. satırdakiyle aynı olabilir. 23. satırdaki uygulamada:
- [value] parametresinin türü atlanmıştır. Bu durumda, [getSomething]'in imzasında bulunan [double] türü kullanılacaktır;
- lambda kodu parantez içine alınmamıştır. Bu durumda lambda'nın sonucu, bu koddaki tek ifadenin değeridir; burada: String.format("ib2.lambda(%s)", value);
27-29. satırlardaki uygulamada:
- [value] parametresinin türü açıkça belirtilir;
- Lambda sonucunu döndürmek için [return] kullanılır. Bu durumda, küme parantezleri koymak gerekir;
- 32-37. satırlar: çeşitli isimsiz fonksiyonlar ve lambda'lar çağrılır;
Elde edilen sonuç şöyledir:
4.2. Örnek-02 - Predicate<T> işlevsel arayüzü
![]() |
Çoğu zaman, kendimizin tanımladığı fonksiyonel arayüzlerden ziyade, kütüphanelerdeki fonksiyonel arayüzlerle uğraşırız. Burada, Java 8'in işlevsel arayüzlerinin çoğunu bir araya getiren [java.util.function] paketinde tanımlanan [Predicate] işlevsel arayüzüyle ilgileniyoruz. Bu arayüz şu şekilde tanımlanmıştır:

Daha önce bir işlevsel arayüzün yalnızca bir yönteme sahip olduğunu belirtmiştik. Oysa burada dört yöntem bulunmaktadır. Java 8’in getirdiği bir diğer yenilik, [default] anahtar sözcüğüyle karakterize edilen arayüzün varsayılan yöntemi kavramının getirilmesidir. Burada bu tür üç yöntem bulunmaktadır. Bu yöntemlerin özelliği, varsayılan bir uygulamaya sahip olmalarıdır. Dolayısıyla, varsayılan yöntemleri olan bir arayüzü uygulayan bir sınıfın bu yöntemleri uygulaması zorunlu değildir. Böylece, [Predicate] arayüzünü uygulamak isteyen bir sınıfın zorunlu olarak uygulaması gereken tek bir yöntem vardır: [test] yöntemi. Dolayısıyla [Predicate] arayüzü, işlevsel bir arayüzdür. Buna göre, işlevsel bir arayüz, uygulamasında yalnızca bir zorunlu yöntem içeren arayüzdür. Birden fazla yöntemi varsa, diğer yöntemlerin [default] anahtar sözcüğünü içermesi gerekir.
[Predicate<T>.test] yöntemi, T türünde bir parametre alır ve bir boole değeri döndürür. Bu arayüz genellikle koleksiyonları filtrelemek için kullanılır. Kullanımını örneklemek için aşağıdaki verileri kullanacağız:
package dvp.data;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Personne {
public enum Sexe {HOMME,FEMME};
// veriler
private String nom;
private int age;
private double poids;
private Sexe sexe;
// yapıcılar
public Personne() {
}
public Personne(String nom, Sexe sexe, int age, double poids) {
this.nom = nom;
this.sexe=sexe;
this.age = age;
this.poids = poids;
}
// alıcı ve ayarlayıcılar
...
// toString
@Override
public String toString(){
try {
return new ObjectMapper().writeValueAsString(this);
} catch (JsonProcessingException e) {
return e.getMessage();
}
}
}
- 32-38. satırlar: [toString] yöntemi, kişinin jSON dizesini döndürür;
[Personnes] sınıfı, 3 kişiden oluşan bir liste tanımlar:
package dvp.data;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.List;
public class Personnes {
private static List<Personne> personnes = Arrays.asList(new Personne("jean", Personne.Sexe.HOMME, 20, 70),
new Personne("marie", Personne.Sexe.FEMME, 10, 30), new Personne("camille", Personne.Sexe.FEMME, 30, 55));
public static List<Personne> get() {
return personnes;
}
public static String toString(List<Personne> liste) {
try {
return new ObjectMapper().writeValueAsString(liste);
} catch (JsonProcessingException e) {
return e.getMessage();
}
}
}
- satır 10-11: 3 kişiden oluşan liste;
- 13-15. satırlar: bu listeyi elde etmek için statik bir yöntem;
- satır 17-23: parametre olarak geçirilen bir kişi listesinden jSON dizesini elde etmeyi sağlayan statik bir yöntem;
Bu veriler aşağıdaki kod tarafından işlenecektir:
package dvp.java8.lambdas;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
import dvp.data.Personne;
import dvp.data.Personnes;
public class Exemple02 {
public static void main(String[] args) {
// anonim sınıf tarafından uygulanan predikat
Predicate<Personne> filterPoids=new Predicate<Personne>() {
@Override
public boolean test(Personne personne) {
return personne.getPoids()<50;
}
};
// bir lambda tarafından uygulanan predikat
Predicate<Personne> filterAge = p -> p.getAge() < 28;
// kişi listesi
List<Personne> personnes = Personnes.get();
// görüntülemeler
System.out.println(Personnes.toString(filterPersonnes(personnes, filterAge)));
System.out.println(Personnes.toString(filterPersonnes(personnes, filterPoids)));
}
private static List<Personne> filterPersonnes(List<Personne> personnes, Predicate<Personne> filter) {
// [filter] listesini filtreler [personnes]
List<Personne> personnesFiltrées = new ArrayList<>();
for (Personne p : personnes) {
if (filter.test(p)) {
personnesFiltrées.add(p);
}
}
return personnesFiltrées; }
}
- satır 13-18: Predicate<Kişi> arayüzünün isimsiz bir sınıfla uygulanması. Bu, kişinin kilosuna göre bir filtredir;
- 20. satır: Predicate<Kişi> arayüzünün bir lambda fonksiyonu ile uygulanması. Bu, kişinin yaşına göre bir filtredir. Daha önce belirtildiği gibi, bu kod şu şekilde de yazılabilirdi:
Predicate<Personne> filterAge = (Personne p) -> {
return (p.getAge() < 28);
};
ancak 20. satırdaki versiyon daha özlüdür. p parametresinin türü bağlamdan çıkarılır. Burada [Predicate<Personne>] türü oluşturulur. Dolayısıyla, uygulanan yöntemin imzası [boolean test(Personne param)] olur. Bu nedenle, 20. satırdaki p'in örtük türü, [Personne] türüdür;
- 22. satır: önceden tanımlanmış bir kişi listesi alınır;
- 24. satır: kişiler yaşlarına göre filtrelenir;
- 25. satır: Kişiler kilolarına göre filtrelenir. Her iki durumda da, filtrelenmiş listeden jSON dizesi görüntülenir;
- 28-37. satırlar:
- parametre olarak filtrelenecek kişi listesini ve filtreyi kabul eder. Filtre, [Predicate<Personne>] arayüzünün bir örneğidir. Dilin yaygın kullanımına uygun olarak, burada ve belgenin diğer yerlerinde, bir arayüz I'nin örneği derken, I'yi uygulayan bir sınıf C'nin örneğini kastediyoruz;
- sonuç olarak, bu şekilde filtrelenmiş listeyi döndürür;
- satır 32: [Predicate] arayüzünün [test] yöntemi kullanılır. Yönteme aktarılan filtreye bağlı olarak, [test] yöntemi:
return personne.getPoids()<50;
ya da
return p.getAge() < 28
[Exemple02] sınıfının çalıştırılması şu sonucu verir:
4.3. Örnek-03 - Function<T,R> işlevsel arayüzü
![]() |
Fonksiyonel arayüz Function<T,R> şu şekilde tanımlanmıştır:

Arayüzün tek yöntemi, R apply(T t) imzasına sahiptir. Genellikle bir Collection<T> türünden yeni bir Collection<R> türü oluşturmak için kullanılır. Bu arayüzü örneklemek için aşağıdaki kodu kullanacağız:
package dvp.java8.lambdas;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import dvp.data.Personne;
import dvp.data.Personnes;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
public class Exemple03 {
public static void main(String[] args) throws JsonProcessingException {
// anonim sınıfla uygulama
Function<Personne, String> mapToName = new Function<Personne, String>() {
@Override
public String apply(Personne personne) {
return personne.getNom();
}
};
// lambda ile uygulama
Function<Personne, Integer> mapToAge = p -> p.getAge();
// kişi listesi
List<Personne> personnes = Personnes.get();
// jSON
ObjectMapper jsonMapper = new ObjectMapper();
// görüntülemeler
System.out.println(jsonMapper.writeValueAsString(mapPersonnes(personnes, mapToName)));
System.out.println(jsonMapper.writeValueAsString(mapPersonnes(personnes, mapToAge)));
}
// List<Kişi> --> List<T> dönüşümü
private static <T> List<T> mapPersonnes(List<Personne> personnes, Function<Personne, T> mapper) {
List<T> maps = new ArrayList<>();
for (Personne p : personnes) {
maps.add(mapper.apply(p));
}
return maps;
}
}
- 15-20. satırlar: [Function<Personne, String>] arayüzünü, Personne --> String dönüşümünü gerçekleştirecek anonim bir sınıfla uyguluyoruz;
- 22. satır: [Function<Personne, Integer>] arayüzünü, Personne --> Integer dönüşümünü gerçekleştirecek bir lambda fonksiyonu ile uyguluyoruz;
- 33-39. satırlar:
- iki parametre kabul eder: ilki List<Personne> türünde olup dönüştürülecek kişilerin listesidir. İkincisi Function<Kişi, T> türünde olup, listedeki her kişiden T türünde bir nesne oluşturan bir işlevdir;
- sonuç olarak, her bir elemanı Kişi -> T dönüşümünden elde edilen List<T> türünde bir liste döndürür;
- 35-37. satırlar: Personne -> T dönüşümü uygulanır. Yöntemin ikinci parametresi [mapToName] nesnesi ise, Personne -> String dönüşümü gerçekleştirilir. [mapToAge] nesnesi ise, Kişi -> Integer dönüşümü gerçekleştirilir;
Elde edilen sonuç şöyledir:
4.4. Örnek-04 - Consumer<T> işlevsel arayüzü
![]() |
Consumer<T> işlevsel arayüzü şu şekilde tanımlanmıştır:

Arayüzün tek yöntemi şu imzaya sahiptir: void accept(T t). Bu yöntem, parametresini kullanır (tüketir) ve herhangi bir sonuç döndürmez. Bunu örneklemek için aşağıdaki kodu kullanacağız:
package dvp.java8.lambdas;
import java.util.List;
import java.util.function.Consumer;
import dvp.data.Personne;
import dvp.data.Personnes;
public class Exemple04 {
public static void main(String[] args) {
// kişi listesi
List<Personne> personnes = Personnes.get();
// anonim uygulama
Consumer<Personne> consumerAge = new Consumer<Personne>() {
@Override
public void accept(Personne personne) {
System.out.printf(" age de %s = %s%n", personne.getNom(), personne.getAge());
}
};
// lambda uygulaması
Consumer<Personne> consumerPoids = p -> System.out.printf(" poids de %s = %s%n", p.getNom(), p.getPoids());
// görüntülemeler
for (Personne p : personnes) {
consumerAge.accept(p);
}
System.out.println("--------");
for (Personne p : personnes) {
consumerPoids.accept(p);
}
}
}
- 14-19. satırlar: [Consumer<Personne>] arayüzü, [accept] yöntemi ile kişinin adını ve yaşını görüntüleyen isimsiz bir sınıf tarafından uygulanmaktadır;
- 21. satır: [Consumer<Personne>] arayüzü, [accept] adlı örtük yöntemi ile kişinin adını ve kilosunu görüntüleyen bir lambda fonksiyonu tarafından uygulanır;
- 23-25. satırlar: Kişi listesi, [consumerAge] uygulaması tarafından kullanılır;
- 27-29. satırlar: Kişi listesi, [consumerPoids] uygulaması tarafından kullanılır;
Sonuçlar şöyledir:
4.5. Örnek-05 - BiConsumer<T,U> işlevsel arayüzü
![]() |
BiConsumer<T,U> işlevsel arayüzü şu şekilde tanımlanmıştır:

Arayüzün tek yöntemi şu imzaya sahiptir: void accept(T t, U u). Bu yöntem, T türünü ve U u ek bilgisini kullanır. Kullanımını aşağıdaki kodla göstereceğiz:
package dvp.java8.lambdas;
import dvp.data.Personne;
import dvp.data.Personnes;
import java.util.List;
import java.util.function.BiConsumer;
public class Exemple05 {
public static void main(String[] args) {
// kişi listesi
List<Personne> personnes = Personnes.get();
// anonim uygulama
BiConsumer<Personne, Integer> biconsumerAge = new BiConsumer<Personne, Integer>() {
@Override
public void accept(Personne personne, Integer integer) {
personne.setAge(personne.getAge() + integer);
System.out.printf("age de %s = %s%n", personne.getNom(), personne.getAge());
}
};
// lambda uygulaması
BiConsumer<Personne, Integer> biconsumerPoids = (p, i) -> {
p.setPoids(p.getPoids() + i);
System.out.printf("poids de %s = %s%n", p.getNom(), p.getPoids());
};
// görüntülemeler
for (Personne p : personnes) {
biconsumerAge.accept(p, 100);
}
System.out.println("--------");
for (Personne p : personnes) {
biconsumerPoids.accept(p, 200);
}
}
}
- 14-20. satırlar: BiConsumer<T,U> arayüzünün isimsiz bir sınıfla uygulanması. [apply] yöntemi, ikinci parametresini kullanarak ilk parametre olarak geçirilen kişinin yaşını günceller. Ardından sonucu görüntüler;
- satır 22-25: BiConsumer<T,U> arayüzünün bir lambda fonksiyonu ile uygulanması. Örtük [apply] yöntemi, ikinci parametresini kullanarak ilk parametre olarak geçirilen kişinin kilosunu günceller. Ardından sonucu görüntüler;
- satır 27-29: Kişi listesi, [biconsumerAge] uygulamasıyla işlenir;
- satır 31-33: Kişi listesi, [biconsumerPoids] uygulamasıyla işlenir;
Elde edilen sonuçlar şunlardır:
4.6. Örnek-06 - BiFunction<T,U,R> işlevsel arayüzü
![]() |
BiFunction<T,U,R> işlevsel arayüzü şu şekilde tanımlanmıştır:

Arayüzün tek yöntemi şu imzaya sahiptir: R apply(T t, U u). Bu yöntem, [BiConsumer.apply] yöntemine benzemektedir; ancak ikincisi bir sonuç döndürmezken, [BiFunction.apply] yöntemi bir sonuç döndürür. Kullanımını aşağıdaki kodla göstereceğiz:
package dvp.java8.lambdas;
import java.util.List;
import java.util.function.BiFunction;
import dvp.data.Personne;
import dvp.data.Personnes;
public class Exemple06 {
public static void main(String[] args) {
// kişi listesi
List<Personne> personnes = Personnes.get();
// anonim uygulama
BiFunction<Personne, Integer, Integer> biFunctionAge = new BiFunction<Personne, Integer, Integer>() {
@Override
public Integer apply(Personne personne, Integer integer) {
return personne.getAge() + integer;
}
};
// lambda uygulaması
BiFunction<Personne, Integer, Double> biFunctionPoids = (p, i) -> {
return p.getPoids() + i;
};
// görüntülemeler
for (Personne p : personnes) {
System.out.printf("age de %s = %s%n", p.getNom(), biFunctionAge.apply(p, 100));
}
System.out.println("--------");
for (Personne p : personnes) {
System.out.printf("poids de %s = %s%n", p.getNom(), biFunctionPoids.apply(p, 200));
}
}
}
- 14-19. satırlar: BiFunction<Personne, Integer, Integer> arayüzü, isimsiz bir sınıfla uygulanmaktadır. Bu sınıfın [apply] yöntemi, ilk parametre olarak geçirilen kişinin yaşına ikinci parametrenin değerini ekleyerek sonucu döndürür;
- 21-23. satırlar: BiFunction<Kişi, Tamsayı, Çift> arayüzü bir lambda işleviyle uygulanmıştır. [apply] yöntemi, birinci parametre olarak geçirilen kişinin ağırlığına ikinci parametrenin değerini ekleyerek sonucu döndürür;
- satır 25-27: [biFunctionAge] uygulaması kişilere uygulanır;
- 29-31. satırlar: [biFunctionPoids] uygulaması kişilere uygulanır;
Elde edilen sonuçlar şunlardır:
age de jean = 120
age de marie = 110
age de camille = 130
--------
poids de jean = 270.0
poids de marie = 230.0
poids de camille = 255.0
Lambda işlevlerinin yanı sıra, Java 8, T türündeki öğelerden oluşan bir akışı modelleyen Stream<T> türünü de getirmiştir. Bu öğeler, lambda işlevleriyle uygulanan ardışık dönüşümlerden geçebilir. Mümkün olduğunda ve birden fazla işlemci varsa, bu dönüşümler bazen paralel olarak gerçekleştirilebilir.
4.7. Örnek-07 - Supplier<T> işlevsel arayüzü
![]() |
Supplier<T> işlevsel arayüzü şu şekilde tanımlanmıştır:

Arayüzün tek yöntemi, T get() imzasına sahiptir ve bu yöntemin görevi, T türünde bir nesne sağlamaktır.
Bu işlevsel arayüzü aşağıdaki kodla göstereceğiz:
package dvp.java8.lambdas;
import java.util.List;
import java.util.Random;
import java.util.function.Supplier;
import dvp.data.Personne;
import dvp.data.Personnes;
public class Exemple07 {
public static void main(String[] args) {
// anonim uygulama
Supplier<Personne> supplier = new Supplier<Personne>() {
// kişi listesi
List<Personne> personnes = Personnes.get();
// arayüz uygulaması
@Override
public Personne get() {
int i = new Random().nextInt(personnes.size());
return personnes.get(i);
}
};
// değerlendirme
for (int i = 0; i < 5; i++) {
affiche(supplier);
}
}
// Kişi görüntüleme
public static void affiche(Supplier<Personne> supplier) {
System.out.println(supplier.get());
}
}
- 13-28. satırlar: Supplier<Personne> türünün uygulaması;
- 31-33. satırlar: [affiche] statik yöntemi, Supplier<Personne> türünde bir parametre bekler;
- 25-27. satırlar: Supplier<Personne> örneğinin çalıştırılması;
Aşağıdaki sonuçlar elde edilir:






