Метод reduce

Последнее обновление: 06.11.2020

Метод reduce выполняет терминальные операции сведения, возвращая некоторое значение - результат операции. Он имеет следующие формы:

Optional<T> reduce(BinaryOperator<T> accumulator)
T reduce(T identity, BinaryOperator<T> accumulator)
U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)

Первая форма возвращает результат в виде объекта Optional<T>. Например, вычислим произведение набора чисел:

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
    } 
}

Объект BinaryOperator<T> представляет функцию, которая принимает два элемента и выполняет над ними некоторую операцию, возвращая результат. При этом метод reduce сохраняет результат и затем опять же применяет к этому результату и следующему элементу в наборе бинарную операцию. Фактически в данном случае мы получим результат, который будет равен: n1 op n2 op n3 op n4 op n5 op n6, где op - это операция (в данном случае умножения), а n1, n2, ... - элементы из потока.

Затем с помощью метода get() мы можем получить собственно результат вычислений: result.get()

Или еще один пример - объединение слов в предложение:

Stream<String> wordsStream = Stream.of("мама", "мыла", "раму");
Optional<String> sentence = wordsStream.reduce((x,y)->x + " " + y);
System.out.println(sentence.get());

Вторая версия метода reduce() принимает два параметра:

T reduce(T identity, BinaryOperator<T> accumulator)

Первый параметр - T identity - элемент, который предоставляет начальное значение для функции из второго параметра, а также предоставляет значение по умолчанию, если поток не имеет элементов.

Второй параметр - BinaryOperator<T> accumulator, как и первая форма метода reduce, представляет ассоциативную функцию, которая запускается для каждого элемента в потоке и принимает два параметра. Первый параметр представляяет промежуточный результат функции, а второй параметр - следующий элемент в потоке. Фактически код этого метода будет равноценен следующей записи:

T result = identity;
for (T element : this stream)
	result = accumulator.apply(result, element)
return result;

То есть при первом вызове функция accumulator в качестве первого параметра принимает значение identity, а в качестве второго параметра - первый элемент потока. При втором вызове первым параметром служит результат первого вызова функции accumulator, а вторым параметром - второй элемент в потоке и так далее. Например:

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

Фактически здесь выполняется следующая цепь операций: identity op n1 op n2 op n3 op n4...

В предыдущих примерах тип возвращаемых объектов совпадал с типом элементов, которые входят в поток. Однако это не всегда удобно. Возможно, мы захотим возвратить результат, тип которого отличается от типа объектов потока. Например, пусть у нас есть следующий класс Phone, представляющий телефон:

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;
    }
}

И мы хотим найти сумму цен тех телефонов, у которых цена меньше определенного значения. Для этого используем третью версию метода 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

Опять же здесь в качестве первого параметра идет значение по умолчанию - 0. Второй параметр производит бинарную операцию, которая получает промежуточное значение - суммарную цену текущего и предыдущего телефонов. Третий параметр представляет бинарную операцию, которая суммирует все промежуточные вычисления.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850