Агрегування Елементів за Допомогою Методу reduce()
Свайпніть щоб показати меню
Під час роботи з колекціями у Java часто виникає потреба згрупувати всі елементи в один результат, наприклад, суму, добуток або інше агреговане значення.
Існує три варіанти методу reduce(), кожен з яких призначений для різних сценаріїв. Розглянемо кожен з них детальніше.
reduce() з одним параметром
Якщо потрібно агрегувати елементи без початкового значення, можна використати цю версію reduce(). Оскільки потік може бути порожнім, метод повертає Optional<T>.
Optional<T> reduce(BinaryOperator<T> accumulator);
Цей метод застосовує функцію accumulator до всіх елементів потоку та повертає Optional<T>.
Практичний приклад
Уявіть інтернет-магазин зі списком товарів та їх цін. Мета — обчислити загальний дохід від усіх товарів у магазині.
Main.java
1234567891011121314151617181920212223242526272829303132333435363738package com.example; import java.util.List; import java.util.Optional; public class Main { public static void main(String[] args) { List<Product> products = List.of( new Product("Laptop", 1200.0), new Product("Mouse", 25.0), new Product("Keyboard", 75.0) ); Optional<Double> totalRevenue = products.stream() .map(Product::getPrice) .reduce(Double::sum); totalRevenue.ifPresent(revenue -> System.out.println("Total revenue: " + revenue)); } } class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } }
Цей код створює список продуктів, а потім використовує reduce() для підсумовування цін. Метод map(Product::getPrice) витягує ціну кожного продукту, а Double::sum виконує додавання. Якщо результат присутній, він виводиться.
reduce() з двома параметрами
Щоб забезпечити гарантоване повернення значення, навіть якщо потік є порожнім, використовуйте метод reduce() з ідентифікуючим параметром. Початкове значення гарантує стабільність обчислення.
T reduce(T identity, BinaryOperator<T> accumulator);
Ця версія reduce() починається з заданого значення identity, що гарантує отримання результату навіть для порожнього потоку.
Практичний приклад
Припустимо, що у магазині є каса з початковим балансом, і потрібно додати загальну вартість усіх товарів, щоб визначити потенційну загальну суму готівки.
Main.java
12345678910111213141516171819202122232425262728293031323334353637package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Product> products = List.of( new Product("Laptop", 1200.0), new Product("Mouse", 25.0), new Product("Keyboard", 75.0) ); double totalRevenue = products.stream() .map(Product::getPrice) .reduce(500.0, Double::sum); System.out.println("Total revenue with initial balance: " + totalRevenue); } } class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } }
Тут код витягує ціни за допомогою map(Product::getPrice) і застосовує reduce(500.0, Double::sum), де 500.0 означає початковий баланс, а Double::sum підсумовує значення.
reduce() для паралельної обробки
Ця версія reduce() призначена для випадків, коли потрібні більш складні перетворення і результати необхідно агрегувати у паралельному режимі.
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
Цей метод приймає три параметри:
identity– початкове значення;accumulator– функція, яка перетворює кожен елемент;combiner– функція, яка об'єднує часткові результати.
Практичний приклад
В інтернет-магазині необхідно обчислити загальну кількість символів у всіх назвах товарів. Це може бути корисно для встановлення обмежень на довжину чека.
Main.java
123456789101112131415161718192021222324252627282930313233343536package com.example; import java.util.List; public class Main { public static void main(String[] args) { List<Product> products = List.of( new Product("Laptop", 1200.0), new Product("Mouse", 25.0), new Product("Keyboard", 75.0) ); int totalLength = products.stream() .reduce(0, (sum, product) -> sum + product.getName().length(), Integer::sum); System.out.println("Total name length: " + totalLength); } } class Product { private String name; private double price; public Product(String name, double price) { this.name = name; this.price = price; } public String getName() { return name; } public double getPrice() { return price; } }
Код ітерує через список продуктів за допомогою reduce(), де 0 — це початкове значення, (sum, product) -> sum + product.getName().length() визначає логіку для підсумовування довжин імен продуктів, а Integer::sum об'єднує результати у середовищі паралельної обробки.
1. Який тип даних повертає reduce(BinaryOperator<T> accumulator), якщо потік може бути порожнім?
2. Коли слід використовувати reduce(T identity, BinaryOperator<T> accumulator)?
Дякуємо за ваш відгук!
Запитати АІ
Запитати АІ
Запитайте про що завгодно або спробуйте одне із запропонованих запитань, щоб почати наш чат