Lambda ifadeleri, fonksiyon yazımının tek satıra indirgenmiş halidir. Bir fonksiyon görevi gördüğü için daha çok fonksiyonel dillerde kullanılmakla birlikte, Java8'den sonra Java dilinde de yerini almıştır.
Lambda ifadelerini tanımlamak için arrow function dediğimiz fonksiyonlardan kullandığımız, -> şeklinde olan arrow operatörünü kullanırız. Örneğin;
() - > 5 yukarıdaki ifade en basit haliyle bir arrow function'dır. Bu örnekte; soldaki parantez ifadesi bir veya birden fazla parametre alırken, sağ taraftaki 5 sayısı ise fonksiyonun bize ne döndürdüğünü gösterir.
Bu arrow function'ı normal bir fonksiyonda(metotta) yazarsak ise aşağıdaki ifadeye denk gelir:
int getValue(){
return 5;
}Lambda ifadeleri tek başlarına anlam ifade etmezler, çünkü aslında sadece bir metot implementasyonudur. Bu yüzden fonksiyonel interface gibi tek bir işin yapıldığı bir sınıfa ait olmalıdırlar.
Fonksiyonel interface'ler içerisinde abstract metot bulunduran interface'lerdir ve bu abstract metotlar da sadece tek bir iş yapacak şekilde oluşturulur.
interface MyValue{
int getValue();
}Yukarıda abstract metot bulunduran bir fonksiyel interface örneği görüyoruz. Bunu lambda ifadeleri ile çağırmak istersek aşağıdaki gibi yazarız:
MyValue value = () -> 5;Bu örnekteki gibi metot imzasını ve lambda ifadelerini doğru verdiğimiz sürece abstract metot çağırma işlemini sadece tek bir satır ile yapabiliriz.
Lambda ifadelerinin bir diğer özelliği; tek bir fonksiyonel interface'den birden fazla lambda metodu oluşturulabilmesidir. Bir örnek verelim. Diyelim aşağıdaki gibi bir fonksiyonel interface'imiz var:
public interface MyTest{
boolean test(int a, int b);
}
public class Main{
public static void main(String[] args){
MyTest lessThan = (x,y) -> x<y;
System.out.println("3 is less than 5 "+lessThan.test(3,5));
MyTest moreThan = (x,y) -> x>y;
System.out.println("3 is more than 5 "+lessThan.test(3,5));
}
}Output:
3 is less than 5 true
3 is more than 5 falseYukarıdaki örnekte gördüğümüz gibi, MyTest isimli fonksiyonel interface'imizdeki test metodumuzu hem lessThan hem de moreThan metotları ile ilişkilendirmiş olduk. Böylece doğru koşulları yazdığımız zaman tek bir abstract metodumuz birden fazla lambda metodu için çalışmış oldu.
Bu basit bir örnekti ama gerçek hayatta lambda ile çözebileceğimiz daha zor problemler olabilir. Bu gibi durumlarda da block lambda dediğimiz birden fazla koşula veya duruma dayalı lambda ifadelerini kullanırız. Yine çok karmaşık olmayan ama basit de olmayan bir örnekle açıklayalım.
public interface MyFunc{
String function(int a);
}
public class Main{
public static void main(String[] args){
MyFunc isPositiveOrNegative = (x) ->{
String result="";
result = x > 0 ? "Positive" : "Negative";
return result;
};
System.out.println(isPositiveOrNegative.function(15));
System.out.println(isPositiveOrNegative.function(-15));
}
}Output:
Positive
NegativeYukarıdaki örneğimizde birden fazla koşula bağlı bir durumu ele aldık. Bu yüzden bunu if-else gibi de düşünebilirsiniz. Örneğimizde; MyFunc isimli fonksiyonel interface'imizde String dönen ve int tipinde parametre alan bir metot yarattık. Bunu main class'ımızda isPositiveOrNegative metodumuzla ilişkilendirdik. Bu metot şunu yapıyor; int tipindeki parametremiz yani x sıfırdan büyükse ('?' if olarak düşünülebilir) "Positive" yaz, değilse(':' else olarak düşünülebilir) "Negative" yaz. İşte bu kadar basit.
Görüldüğü gibi Lambda ifadeleri işimizi kolaylaştırmakla kalmayıp bizi kod kalabalığından da kurtarıyor. Bu konuda daha detaylı bilgi edinmek için tutorial'ları da inceleyebilirsiniz.
Bir arayüz veya soyut sınıf üzerinden tanımlanan ve ismi olmayan sınıflara anonim sınıf denir. Bu sınıflar oluşturuldukları anda kullanılırlar. Anonim sınıfların bir örneğini alamazsınız; çünkü isimleri yoktur.
Şimdi anonim sınıfları anlayabilmek için bir örnek yapalım. Öncelikle bir arayüz tanımlayalım:
public interface Operation
{
int operate(int x, int y);
}Operation isminde bir arayüz tanımladık ve içine operate() adında bir metot yazdık. Bu metot int türünde iki sayıyı parametre olarak alır, bu sayılar üzerinde bir işlem yapar ve sonucu yine int türünde döndürür.
Şimdi bu arayüzü kullanan bir metot yazalım:
public class Math
{
public static int operateTwoNumbers(int x, int y, Operation operation)
{
return operation.operate(x, y);
}
}Math adında bir sınıf tanımladık ve bu sınıf içinde statik operateTwoNumbers() metodunu yazdık. Bu metot int türünde iki sayıyı parametre alıyor ve bu sayılar üzerinde bir işlem yapıyor; fakat bu işlemin nasıl yapılacağını yine parametre olarak aldığımız Operation türündeki nesneden öğreniyoruz.
Şimdi, iki sayıyı toplayan bir Operation sınıfı yazalım:
public class AdditionOperation implements Operation
{
@Override
public int operate(int x, int y)
{
return x + y;
}
}Şimdi aşağıdaki işlemi gerçekleştirebiliriz:
int result = Math.operateTwoNumbers(5, 10, new AdditionOperation());
System.out.println(result);Bu kodu çalıştırdığınızda konsola 15 yazar; çünkü AdditionOperation sınıfı toplama işlemi yapmaktadır. Fakat burada şunu düşünelim: diyelim ki, bu metodu sadece bir kez kullandık. Sadece bir kez kullandığımız bu metot için AdditionOperation adında bir sınıf yazmamıza gerek var mıdır?
Bunun yerine anonim sınıfları kullanabilirdik. Şimdi yukarıdaki kodu anonim sınıf kullanarak tekrar yazalım:
int result = Math.operateTwoNumbers(5, 10, new Operation()
{
@Override
public int operate(int x, int y)
{
return x + y;
}
});
System.out.println(result);Kalın olarak belirttiğimiz kod anonim sınıf kodudur. Gördüğünüz gibi, new deyimini kullanarak Operation türünde bir nesne oluşturduk; fakat bildiğiniz gibi, new deyimini arayüzler üzerinde kullanamayız, yalnızca sınıflar üzerinde kullanabiliriz. Burada da new deyimini kullanarak bir sınıf oluşturduk; fakat bu sınıfın bir ismi yoktur. Bu sınıfla ilgili bildiğimiz tek şey, Operation arayüzünü uyguladığıdır, dolayısıyla operate() metodunu yazmak zorundadır.
Anonim sınıflar, yukarıda da gördüğümüz gibi, bir arayüz veya soyut sınıf üzerinden oluşturulan isimsiz sınıflardır. Bu sayede, bir daha hiçbir zaman kullanmayacağımız AdditionOperation sınıfını yazmamıza gerek kalmaz.
Lambda ifadeleri, anonim sınıf kullanarak yazdığımız kodları daha kısa yazmamıza imkân tanır. Lambda ifadelerini kullanarak, yukarıda yazdığımız kodu aşağıdaki gibi tek satırda da yazabiliriz:
int result = Math.operateTwoNumbers(5, 10, (x, y) -> x + y);
System.out.println(result);Kalın olarak belirttiğimiz kod bir lambda ifadesidir. Gördüğünüz gibi, anonim sınıf yerine lambda ifadesi kullandığımız zaman kodu tek satıra indirgedik.
Şimdi, lambda ifadelerini daha ayrıntılı incelemeden önce, fonksiyonel arayüzlerden bahsedelim.
1) Arrow function nedir?
Cevap: Sadece kendi fiziksel ortamını etkileyen, girdisi ve çıktısı olan matematiksel bir ifadeye benzeyen, kısaltılmış bir fonksiyon ifadesidir.
2) Lambda ifadelerinde ? ve : ifadelerinin Java dilindeki karşılığı nedir?
Cevap: if-else koşul ifadelerinin karşılığıdır.