Daha önceki yazılarımızda Lambda ifadelerinden ve Fonskiyonel arayüzlerden bahsetmiştik. Şimdi ise, java.util.function
paketi altında yer alan ve gömülü olarak bulunan fonksiyonel arayüzlere değineceğiz.
java.util.function paketi altında, farklı amaçlar için bulunan hazır arayüzler bulunmaktadır. Java 8 içerisinde Lambda deyimlerinin kullanılabilir kılınmasında, java.util.function paketi altındaki arayüzler kullanılmaktadır. Bu fonksiyonel arayüzlere java.util.function adresinden görebilirsiniz.
Bu yazımızda ise, fonksiyonel arayüzlere giriş düşüncesiyle java.util.function.Consumer
arayüzünden ve nasıl kullanıldığından bahsedeceğiz. Consumer
arayüzü accept isimli tek bir metoda sahiptir. Bu fonksiyonun bulunuş amacı, tüketim operasyonlarında kullanılmasıdır. Tüketimden kasıt edilen ise, metoda girdi olması fakat çıktı olmamasıdır. Metod girdisinin tipi ise jenerik olarak T
harfi ile temsil edilmiştir. T
yerine, isteğe göre herhangi bir Java tipi gelebilir. Biz String tipini kullanacağız.
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Consumer arayüzü, yukarıda görüldüğü üzere bir fonksiyonel arayüzdür. Bir arayüzün, fonksiyonel olarak nitelenebilmesi için, tek bir soyut metoda sahip olma şartı vardır. Zaten bu sayede, fonksiyonel arayüzler Lambda deyimlerine öykünebilmektedirler.
Java 8 öncesine göre Consumer arayüzü türünden bir nesneyi anonim bir sınıf ile oluşturulım.
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String msg) {
System.out.println(msg);
}
};
consumer.accept("Merhaba Dünya");
Görüldüğü üzere bir anonim sınıf oluşturduk ve accept metodunu tükettik.
Java 8 sonrası için anonim fonksiyonlar yerine Lambda deyimlerini kullanabilmekteyiz. Örneğin yukarıdaki anonim sınıfı aşağıdaki yer alan Lambda deyimi ile yer değiştirebiliriz.
Consumer<String> consumer = (String msg) -> {
System.out.println(msg);
};
consumer.accept("Merhaba Dünya");
Lambda deyimlerinde odaklanması gereken nokta, fonksiyonel arayüzün tek metodunun sahip olduğu metod girdi tipi, sayısı,sırası ve metod çıktı tipidir. Bu sayede kod satırı olarak tasaruf edilmektedir.
Lambda fonksiyonlarında tanımlanan metod girdi tanımlamalarında, istenirse tip tanımlamasından feragat edilebilir. Yani yukarıdaki Lambda deyimini aşağıdaki gibi yazabiliriz.
Consumer<String> consumer = (msg) -> {
System.out.println(msg);
};
consumer.accept("Merhaba Dünya");
Görüldüğü gibi, (String msg) tanımlamasını (msg) yapabildik. Sol tarafta zaten String tip bilgisi yer aldığından, compiler metod girdisinin tipini buradan elde edecektir. Tip tanımlamalarından feragat ettiğimiz gibi parantezden de kurtulabiliriz.
Consumer<String> consumer = e -> {
System.out.println(e);
};
consumer.accept("Merhaba Uranüs");
JDK 8 in çekirdeğinde java.util.function arayüzleri halihazırda kullanılmaktadır. Örneğin Iterable arayüzünün içerisinde forEach metodunda Consumer arayüzü kullanılmaktadır.
public interface Iterable<T> {
...
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
...
}
forEach metodu, önce null kontrolü yapmakta ve ardından, döngüsel olarak mevcut veri tipi üzerinde veri tüketimi yapmaktadır. Şimdi bu metodu kullanan basit bir örnek yazalım.
List<String> names = Arrays.asList("Ali", "Veli", "Selami");
names.forEach(consumer);
// veya
names.forEach(e -> {
System.out.println(e);
});
Bu örnek içerisinde her bir isim bilgisi tek tek konsol ekranına çıktılanmaktadır.
Java 8 evvelinde bir metodu referans olarak kullanma şansı bulunmuyordu. Fakat Java 8 ile birlikte Java metodlarını referans olarak kullanabiliyoruz. Örneğin, elimizde halihazırda aşağıdaki gibi bir listele metodu bulunsun.
public class App{
public static void listele(String e) {
System.out.println(e);
}
}
Dikkat edilirse bu metodun girdi ve çıktı normu, Consumer#accept metodunun girdi ve çıktı biçimiyle birebir aynıdır. Bu sebeple, listele metodu metod referansı olarak Consumer tipi için kullanılabilirdir.
Consumer<String> consumer= App::listele;
consumer.accept("Merhaba Dünya");
- Bir metodu referans olarak kullanabilmek için
-
ifadesi kullanılmaktadır. Şimdi metod referans kullanımını örnek olarak forEach metodu üzerinde deneyelim.
List<String> names = Arrays.asList("Ali", "Veli", "Selami");
names.forEach(App::listele);
App#listele
metodunun bir benzerinin yazılmışı zaten PrintStream sınıfı içerisinde var.
List<String> names = Arrays.asList("Ali", "Veli", "Selami");
names.forEach(System.out::print);
// veya
names.forEach(System.out::println);
Şimdilik bu kadar, tekrar görüşmek dileğiyle.