Anotasyon

Java 8 – Stream API (Filter, Sorted, Map, Match, Reduce)

Merhaba arkadaşlar,
mobilhanem.com üzerinden anlattığımız/yayınladığımız derslerimize Java 8 Yenilikleri başlığı altında ikinci yazımız olan Stream API ile Gelen Yenilikler ile devam ediyoruz. Akabinde devam edecek serinin içeriklerini buradan takip edebilirsiniz.

Stream Api nedir?

Hepimiz bir şekilde veri setleri ile işlemler yapıyoruz. En basitinden küçükten büyüğe veya büyükten küçüğe sıralamak bir veri seti işlemi. Veri setleri deyince aklımıza ilk gelen veri yapıları Listeler veya Diziler olabilir. Java 8 ile birlikte gelen Stream Api desteği, veriler üzerinde yapacağımız işlemleri temiz ve anlaşılır bir şekilde ifade edebilmemize olanak sağlıyor.

1. Filter

Bir listeyi bir veya birden çok parametreye göre kısıtlayabiliriz. Örneğin elimizde kullanıcı listeli olsun ve bu listede kullanıcıların bazı kriterlerine göre listeyi indirgeyelim.

User user1 = new User("James", "Gosling", 63);
User user2 = new User("Ken", "Thompson", 75);
User user3 = new User("Richard", "Stallman", 65);

List<User> userList = Arrays.asList(user1, user2, user3);

userList.stream().filter(user -> (user.getSurname().contains("a") && (user.getAge().equals(65))) ).collect(Collectors.toList()).forEach(System.out::println);

Örneğimizde isminde ‘a’ harfi geçenleri ve yaşı 65 olan kullanıcıları filtreleyerek ekrana yazdırmak istediğimi belirttik. Böylelikle sadece user3‘ün bu koşula uyacağı görülmektedir.

2. Sorted

Bir veri setini belirli parametrelere göre sıralamak isteyebiliriz. Örneğin aşağıdaki kod’da kitapların sayfa sayısına göre küçükten büyüğe sıralanışını görebilirsiniz.

Book book1 = new Book("Clean Code", "Robert Cecil Martin", 300);
Book book2 = new Book("Test Driven Development", "Kent Beck", 450);
Book book3 = new Book("Refactoring", "Martin Fowler", 200);

List<Book> bookList = Arrays.asList(book1, book2, book3);

List<Book> bookSortedListByPage = bookList.stream().sorted(Comparator.comparingInt(Book::getPage)).collect(Collectors.toList());
System.out.println(bookSortedListByPage);

Yukarıda bulunan Comparator bir Functional Interface’dir. Functional Interface ile ilgili eksiğiniz var ise bir önce ki Lambda İfadeleri yazımızda değinmiştik inceleyebilirsiniz. Burada comparingInt metodu ile kitapların sayfa sayısına göre sıralama yapacağımızı belirtmiş olduk. Ayrıca comparingDouble, comparingLong gibi seçenekleri da bulunmaktadır. Örneğimize bağlı olarak book3 -> book1 -> book3 şeklinde sıralanacaktır.

3. Map

Map, stream içerisinde erişilen her bir nesneye özgü işlemler yapmamızı sağlar. Örneğin elinizde rakamlar olan bir liste var map ile her rakamın karesini alabilir veya farklı matematiksel işlemler yapabilirsiniz.

Notification notification1 = new Notification(Priority.LOW, "Bilgi", "Hergün yeni bir bilgi!");
Notification notification2 = new Notification(Priority.HIGH, "Hatırlatma", "Alarm kurmayı unutma!");
Notification notification3 = new Notification(Priority.LOW, "Bilgi Tekrar", "Hergün yeni bir bilgi Tekrar!");
Notification notification4 = new Notification(Priority.MEDIUM, "Spor", "Sabah sporun var erken uyu!");

List<Notification> notificationList = Arrays.asList(notification1, notification2, notification3, notification4);

notificationList.stream().map(notification -> notification.getPriority().equals(Priority.LOW)).collect(Collectors.toList()).forEach(System.out::println);

Yukarıdaki örneğimizden yola çıkacak olursak elimizde kullanıcılara göndereceğimiz bir bildirim listesi olsun ve Bildirim sınıfın da tanımlı özellikler ise priority, title ve description olsun. Burada farkedeceksiniz ki priority bir enum ve biz bildirim önceliği LOW olanları bulmak için her bir elemanı map ile işleme tabi tutmuş olduk. Yukarıdaki kodun çıktısı;

true
false
true
false

şeklinde olacaktır çünkü 1 ve 3 numaralı bildirimlerin önceliği LOW.

4. Match

Match operasyonu bir akışın belirli kriterleri sağlayıp sağlamadığını ölçmek için kullanılır. Map den farkı her iterasyonu tek tek değerlendirip sonucu yansıtmaz bunun yerine tüm koleksiyonu değerlendirerek sonucu yansıtmasıdır. Match operasyonunun 3 çeşit kullanımı bulunmaktadır.

4.1 noneMatch

Belirtilen kriter listede hiçbir elemanda bulunmuyor ise true döndürür.

4.2 allMatch

Belirtilen kriter listede tüm elemanlarda bulunuyor ise true döndürür.

4.3 anyMatch

Belirtilen kriter listede herhangi bir elemanlarda bulunuyor ise true döndürür.

Notification notification1 = new Notification(Priority.LOW, "Bilgi", "Hergün yeni bir bilgi!");
Notification notification2 = new Notification(Priority.HIGH, "Hatırlatma", "Alarm kurmayı unutma!");
Notification notification3 = new Notification(Priority.LOW, "Bilgi Tekrar", "Hergün yeni bir bilgi Tekrar!");
Notification notification4 = new Notification(Priority.MEDIUM, "Spor", "Sabah sporun var erken uyu!");

List<Notification> notificationList = Arrays.asList(notification1, notification2, notification3, notification4);

boolean isNoneMatch = notificationList.stream().noneMatch(notification -> notification.getTitle().contains("a"));
boolean isAllMatch = notificationList.stream().allMatch(notification -> notification.getTitle().contains("a"));
boolean isAnyMatch = notificationList.stream().anyMatch(notification -> notification.getTitle().contains("a"));
System.out.println(isNoneMatch + " " + isAllMatch + " " + isAnyMatch);

Yukarıdaki örneğimizde bir önceki adımda kullandığımız bildirim örneği üzerinden gidebiliriz. Bildirim başlığında ‘a’ harfi geçenleri noneMatch, allMatch, anyMatch metodları ile kullandık programın çıktısı şu şekilde olacaktır.

false false true

5. Reduce

Reduce işlemi genelde kümülatif operasyonlarda sıkça kullanılır. Bir veri setinde sırayla işlem yapmak istiyorsanız ve bir önceki yaptığınız işlemi de dahil etmek istiyorsanız reduce metodunu kullanabilirsiniz. Örneğin yukarı da kitap örneğinden yola çıkacak olursak yine aynı 3 tane kitap nesnemiz olsun ve sayfa sayıları 250 den büyük olanları toplasın.

Integer sum = bookSortedListByPage.stream().filter(book -> book.getPage() > 250).map(Book::getPage).reduce(0, (Integer::sum));
System.out.println(sum);

Yukarıda ne yaptığımı adım adım inceleyelim.

İlk önce filter metodu ile kitaplar arasında sayfa sayısı 250 den fazla olanları seçtik, ardından map metodu ile kitapların sayfa değişkenleri üzerinde işlem yapacağımızı belirttik ve reduce ile hangi işlemi yapacağımızı söyledik. Burada aklınıza reduce metodunun ilk parametresine neden 0 verdiğimiz sorusu gelebilir, konunun başında verinin kümülatif olarak işlendiğini söylemiştik yani bir önceki adımda yapılan işlemin bir sonraki adımda kullanılacaktır. Bunun için ilk adımda önceki değer oluşamayacağı için başlangıç değeri olarak tanımlıyoruz.

Daha ayrıntılı bilgiler için burayı inceleyebilirsiniz.

Stream API ile gelen özellikleri elimden geldiğince anlatmaya çalıştım aklınıza takılan bir yer veya sormak istediğiniz bir şey olursa yorum yazabilirsiniz. Umarım faydalı olmuştur.

Hoşçakalın.

27

Yusuf Çakal

Cumhuriyet Üniversitesi - Bilgisayar Mühendisliği (2014-2018)

1 Yorum

  • Merhaba çok güzel açıklamışsınız. .book:: gePage kısmında “: :” bunun anlamı ne oluyor tam olarak acaba?

Haftalık Bülten

Mobilhanem'de yayınlanan dersleri haftalık mail almak ister misiniz?