Nedir bu Java Stream?

Stream kelimesini ilk duyduğum zaman aklıma Java I/O paketinde bulunan InputStream ve OutputStream gelmişti. Fakat bunun böyle olmadığını api dökümanını inceleyince fark ettim. Bu yazıda streamler nasıl çalışır , türleri nelerdir ve nasıl kullanılır sorularını cevaplamaya çalışacağım.

Stream ler fonksiyonel programlama da kullanılan Monad tasarım kalıplarına çok benzemektedir. Türkçe kelime anlamı akıştır. Bir dizi öge üzerinde hesaplamalar yapmak ve farklı türde operasyonlar yapmamızı sağlarlar.

Nasıl çalışır?

Bir stream aslında iki türlü işlem yapar. Bunlar ara işlemler ve sonlandırıcı işlemlerdir. Ara işlemler işlemin sonucunda Stream dönerken sonlandırıcı işlemler void yada stream olmayan türde değer döner.

List<String> list = Arrays.asList(ali, veli, ahmet,mehmet);
list.stream()
.filter(s -> s.startsWith(a))
.map(String::toUpperCase)
.forEach(System.out::println);

Output:ALIAHMET

Örnek olarak yukarıdaki koda baktığımız zaman bir liste içerisinde bulunan ali, veli, ahmet ve mehmet değerlerini ara işlem olan filter ve map methodu ile işleme alıp sonlandırıcı işlemolan forEach methoduyla konsola çıktılarını basmaktadır. Stream’in tüm ara ve sonlandırıcı işlemlerine buradan erişebilirsiniz.

Türleri nelerdir?

Streamler ikiye ayrılır. Bunlar stream() ve parallelStream() dir. stream() methodu bir listede bulunan değerlerin işleme alınmasında sıralı olarak hareket eder. Fakat parallelStream() methodu ise liste de bulunan değerleri birbirinden bağımsız olarak işleme alır. Örnek olarak yukarıda tanımlamış olduğumuz örnek listemizi stream() ve parallelStream() methodlarını ayrı ayrı kullanarak çalıştırırsak stream() methodu her zaman bize aşağıdaki sonucu dönecektir.

Output:ALIAHMET

Fakat parallelStream() methodu ise ilk değer olarak ALI değerini önce dönerken bazende AHMET değerini önce dönecektir. parallelStream() ‘ e yazının ilerleyen kısımlarında daha detaylı değineceğiz.

Yukarıdaki örnek de bir stream oluşturmak için List içerisindeki değerleri .stream() ile işleme almıştık. Aslında buna ihtiyaç duymadan Stream.of() methodu ilede aynı işlemi gerçekleştirebiliriz. Örnek olarak :

 Stream.of(ali, veli, ahmet,mehmet””)
 .filter(s -> s.startsWith(a))
 .map(String::toUpperCase)
 .forEach(System.out::println);
 
 Output:ALIAHMET

Java 8 ile ayrıca primitive type lara özgü stream türleride bulunmaktadır. Örneğin int , double ve long primitive türleri için IntStream , DoubleStream ve LongStream türleri bulunmaktadır.

IntStreamler for döngüsü yerinede kullanabiliriz. Aşağıdaki örnek de for döngüsü ile yapılan bir işlemin IntStream ile yapılmasını göreceğiz.

For döngüsü :

for (int i = 0 ; i < 10 ; i++){ System.out.print(i);}

Output:0123456789

IntStream :

IntStream.range(0,10).forEach(System.out::print);

Output:0123456789

Primitive stream ler aritmetik işlemler olan sum , average , max , min işlemlerinin kolaylıkla yapılmasını sağlarlar. Örnek olarak :

System.out.println(IntStream.range(0,10).max().getAsInt());System.out.println(IntStream.range(0,10).min().getAsInt());

System.out.println(IntStream.range(0,10).sum());System.out.println(IntStream.range(0,10).average().getAsDouble());

Output: 9 //max0 //min45 //sum4.5 //average

Ayrıca primitive streamler obje dönüşümlerinde de kullanılabilir. Örnek olarak :

IntStream.range(0,3).mapToObj(i -> ali+i).forEach(System.out::println);

Output: ali0ali1ali2

Stream’in ikinci türü olan parallelStream ise işleme alınan değerleri sıralı olarak değilde birbirlerinden bağımsız olarak işleme alırlar. Bunu yaparken ForkJoinPool arayüzünün sağlamış olduğu commonPool methodunu kullanır. Thread pool da default tanımlı olan thread adedi kadar olan işlemleri paralel olarak çalıştırabilir.

Arrays.asList(ali, veli, ahmet)
.parallelStream()
.filter(s -> { System.out.format(Filter: %s [%s]\n, s, Thread.currentThread().getName()); return true; })
.map(s -> { System.out.format(Map: %s [%s]\n, s, Thread.currentThread().getName()); return s.toUpperCase(); })
.forEach(s -> System.out.format(ForEach: %s [%s]\n, s, Thread.currentThread().getName()));

Output: 
Filter: ali [ForkJoinPool.commonPool-worker-1]
Map: ali [ForkJoinPool.commonPool-worker-1]
ForEach: ALI [ForkJoinPool.commonPool-worker-1]
Filter: veli [main]
Map: veli [main]Filter: ahmet [ForkJoinPool.commonPool-worker-2]
Map: ahmet [ForkJoinPool.commonPool-worker-2]
ForEach: AHMET [ForkJoinPool.commonPool-worker-2]
ForEach: VELI [main]

Yukarıdaki örnek de parallelStream in nasıl çalıştığını daha iyi görebilirsiniz.

Özetle Java programlama dili, Java 8 versiyonunda yayınlamış olduğu stream ler ile yazılan kodların daha kolay okunup , güzel görünmesinin yanında performans açısından da hızlı olmasını sağlamıştır.

Kolay Gelsin.. 🤞