16 Ocak 2020 Perşembe

Stream.reduce metodu

Giriş
- Accumulator'e geçilen birinci parametre Identity nesnesidir.Identity başlangıç değerini belirtir.
- Accumulator ikinci parametreyi Identity yani başlangıç nesnesine ekler ve tek bir sonuç döner.
- Combiner paralel stream'lerde kullanılır.

reduce() ve collect() Farkı
reduce() işlemi ile collect() işlemi çok benzerler. Aslında collect() işlemi mutable reduction olarak adlandırılabilir. Aralarındaki fark performanstır. Eğer biz bir sonucu bir container içinde toplamak istersek reduce() yerine collect() kullanmak gerekir
Örnek
Elimizde şöyle bir kod olsun
List<String> list = Arrays.asList("1", "2", "3"); 
  
// Example using the string concatenation operation
System.out.println(list.stream().parallel()
            .reduce("", (s1, s2) -> s1 + s2, (s1, s2)->s1 + s2));
Şöyle yaparız. Burada her şey StringBuilder içinde toplanıyor
System.out.println((StringBuilder)list.stream().parallel()
  .collect(
    StringBuilder::new, 
    StringBuilder::append, 
    StringBuilder::append
  )
);

reduce ve diğer tek sonuç dönen metodlar
Açıklaması şöyle
Stream reduction is an operation that returns one value by combining the elements of a stream. The Java stream api contains a set of predefined reduction operations, such as average(), sum(), min(), max(), and count(). There is one general-purpose operation: reduce().
reduce metodu - Accumulator
İmzası şöyle. Identity yani başlangıç değeri almadığı için Optional döner.
Optional<T> reduce(BinaryOperator<T> accumulator);
Açıklaması şöyle. Accumulator iki tane nesne alır ve bir sonuç döner.
itemAccumulator – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream
Örnek
Şöyle yaparız
Optional<Student> oldestStudent = students.stream()
  .reduce((s1, s2) -> s1.age() > s2.age() ? s1 : s2);
reduce metodu - Identity + Accumulator
Burada Identity yani başlangıç değeri aldığı için Optional dönmesine gerek yok. Direkt değer tipinden bir sonuç döner.

Örnek
Şöyle yaparız
List<Integer> list = ...
Optional<Integer> sum  = list.stream()
  .reduce((a,b) -> a + b); //no identity element provided


List<Integer> list = ...;
Integer sum  = list.stream()
  .reduce(0, (a,b) -> a + b); //identity element provided
Örnek
Şöyle yaparız.
return Stream.of(...)
  .reduce(Stream.empty(), (a,b) -> Stream::concat)
  .collect(Collectors.toList());
reduce metodu - Identity + Accumulator + Combiner
İmzası şöyle.
<U> U reduce(U identity,
             BiFunction<U, ? super T, U> accumulator
             BinaryOperator<U> combiner);
Açıklaması şöyle. Combiner paralel stream'lerde kullanılır.
When a stream executes in parallel, the Java runtime splits the stream into multiple substreams. In such cases, we need to use a function to combine the results of the substreams into a single one. This is the role of the combiner
Açıklaması şöyle. Combiner accumulator parametre tipleri arasında uyumsuzluk varsa kullanılır.
Combiner – a function that takes two parameters: a partial result of the reduction operation and the next element of the stream Combiner – a function used to combine the partial result of the reduction operation when the reduction is parallelized, or when there’s a mismatch between the types of the accumulator arguments and the types of the accumulator implementation
Açıklaması şöyle. Accumulator ve Combiner aynı şeyi yapmalıdır.
Additionally, the combiner function must be compatible with the accumulator function; for all u and t, the following must hold:
combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
Örnek
Şu kod Accumulator toplama, Combiner ise çarpma yaptığı için yanlış.
 List<String> strs = ...

int ijk = strs.stream().reduce(0, 
  (a, b) -> { 
    return a + b.length();
  },
  (a, b) -> {
    return a * b;
  });
Örnek
Elimizde şöyle bir kod olsun. Bu kod derlenmez
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int computedAges = users.stream().reduce(0, 
  (partialAgeResult, user) -> partialAgeResult + user.getAge());
Açıklaması şöyle.
In this case, we have a stream of User objects, and the types of the accumulator arguments are Integer and User. However, the accumulator implementation is a sum of Integers, so the compiler just can’t infer the type of the user parameter.
Düzeltmek için şöyle yaparız
int computedAges = users.stream().reduce(0,
  (partialAgeResult, user) -> partialAgeResult + user.getAge(),
  Integer::sum);


Hiç yorum yok:

Yorum Gönder