Metoda reduce
Metoda reduce efectuează operații terminale de reducere, returnând o valoare care reprezintă rezultatul operației. Are următoarele forme:
Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
Prima formă returnează rezultatul sub formă de Optional<T>. De exemplu, să calculăm produsul unui set de numere:
import java.util.stream.Stream;
import java.util.Optional;
public class Program {
public static void main(String[] args) {
Stream<Integer> numbersStream = Stream.of(1, 2, 3, 4, 5, 6);
Optional<Integer> result = numbersStream.reduce((x, y) -> x * y);
System.out.println(result.get()); // 720
}
}
Obiectul BinaryOperator<T> reprezintă o funcție care acceptă două elemente și efectuează o anumită operație asupra lor, returnând rezultatul. În acest context, metoda reduce păstrează rezultatul și aplică din nou asupra acestuia și asupra următorului element din set operația binară. De fapt, în acest caz, vom obține un rezultat care va fi egal cu: n1 op n2 op n3 op n4 op n5 op n6, unde op este operația (în acest caz, înmulțirea), iar n1, n2, ... sunt elemente din flux.
Apoi, cu ajutorul metodei get(), putem obține rezultatul propriu-zis al calculului: result.get().
Un alt exemplu - unirea cuvintelor într-o propoziție:
Stream<String> wordsStream = Stream.of("mama", "spăla", "rama");
Optional<String> sentence = wordsStream.reduce((x, y) -> x + " " + y);
System.out.println(sentence.get());
A doua versiune a metodei reduce() acceptă doi parametri:
T reduce(T identity, BinaryOperator<T> accumulator)
Primul parametru - T identity - este elementul care oferă valoarea inițială pentru funcția din al doilea parametru și, de asemenea, oferă o valoare implicită dacă fluxul nu are elemente.
Al doilea parametru - BinaryOperator<T> accumulator, la fel ca prima formă a metodei reduce, reprezintă o funcție asociativă care se execută pentru fiecare element din flux și acceptă doi parametri.
Primul parametru reprezintă rezultatul intermediar al funcției, iar al doilea parametru - următorul element din flux. Practic, codul acestei metode va fi echivalent cu următoarea înregistrare:
T result = identity;
for (T element : this stream)
result = accumulator.apply(result, element)
return result;
Adică, la prima apelare, funcția accumulator primește ca prim parametru valoarea identity și ca al doilea parametru - primul element din flux. La a doua apelare, primul parametru este rezultatul primei apelări a funcției accumulator, iar al doilea parametru este al doilea element din flux și așa mai departe. De exemplu:
Stream<Integer> numberStream = Stream.of(-4, 3, -2, 1);
int identity = 1;
int result = numberStream.reduce(identity, (x, y) -> x * y);
System.out.println(result); // 24
De fapt, aici se execută următorul lanț de operații: identity op n1 op n2 op n3 op n4...
În exemplele anterioare, tipul obiectelor returnate coincide cu tipul elementelor care intră în flux. Totuși, acest lucru nu este întotdeauna convenabil. Este posibil să dorim să returnăm un rezultat al cărui tip diferă de tipul obiectelor din flux. De exemplu, să presupunem că avem următoarea clasă Phone, care reprezintă un telefon:
class Phone {
private String name;
private int price;
public Phone(String name, int price){
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public int getPrice() {
return price;
}
}
Și dorim să găsim suma prețurilor telefoanelor al căror preț este mai mic decât o anumită valoare. Pentru aceasta folosim a treia versiune a metodei reduce:
Stream<Phone> phoneStream = Stream.of(new Phone("iPhone 6 S", 54000),
new Phone("Lumia 950", 45000),
new Phone("Samsung Galaxy S 6", 40000),
new Phone("LG G 4", 32000));
int sum = phoneStream.reduce(0,
(x, y) -> {
if(y.getPrice() < 50000)
return x + y.getPrice();
else
return x + 0;
},
(x, y) -> x + y);
System.out.println(sum); // 117000
Și aici, primul parametru este valoarea implicită - 0. Al doilea parametru efectuează o operație binară, care primește valoarea intermediară - prețul total al telefonului curent și al celui anterior. Al treilea parametru reprezintă o operație binară care însumează toate calculele intermediare.