Ответ
reduce — это терминальная операция в Java Stream API, которая выполняет свёртку (агрегацию) элементов потока в одно значение, последовательно применяя функцию-аккумулятор.
Основные формы:
-
С начальным значением (identity):
T reduce(T identity, BinaryOperator<T> accumulator)identity— начальное значение и результат для пустого потока.accumulator— функция, объединяющая текущий результат и следующий элемент.List<Integer> numbers = List.of(1, 2, 3, 4); int sum = numbers.stream() .reduce(0, (a, b) -> a + b); // Результат: 10
-
Без начального значения:
Optional<T> reduce(BinaryOperator<T> accumulator)- Возвращает
Optional, так как для пустого потока результата нет.Optional<Integer> product = numbers.stream() .reduce((a, b) -> a * b); // Optional[24]
- Возвращает
Ключевые моменты:
- Использование: сумма, произведение, поиск максимума/минимума, конкатенация строк.
- Порядок: В параллельных потоках
accumulatorдолжен быть ассоциативным, аidentity— нейтральным элементом (например,0для сложения,1для умножения). - Альтернативы: Для часто используемых операций (
sum,max,min) существуют специализированные методы.
Ответ 18+ 🔞
Ну, слушай, смотри, вот есть у тебя поток, да? Stream там, numbers, хуйня какая-то. И тебе надо всё это добро в одну кучу сгрести. Сумму найти, или всё перемножить, или строки склеить. Вот для этого, блядь, и придумали reduce — операция терминальная, то есть после неё поток, сука, кончается, всё, приехали.
Как это, блядь, работает:
-
С начальным значением (identity):
T reduce(T identity, BinaryOperator<T> accumulator)Тут всё просто, как три копейки.
identity— это твоя стартовая точка, база, хуле. Если поток пустой — вернётся именно это значение, и всё. Аaccumulator— это функция, которая берёт текущий накопленный результат (илиidentityна первом шаге) и следующий элемент из потока, и делает с ними что-то. Например, складывает, ёпта.List<Integer> numbers = List.of(1, 2, 3, 4); int sum = numbers.stream() .reduce(0, (a, b) -> a + b); // Итог: 10Смотри: сначала
a = 0(наш identity),b = 1(первый элемент). Сложили — получили 1. Теперьa = 1,b = 2— сложили, 3. И так далее, пока не проебём все числа. В конце — 10, красота. -
Без начального значения:
Optional<T> reduce(BinaryOperator<T> accumulator)А вот это уже, блядь, поинтереснее. Ты не даёшь стартового значения. А если поток пустой? А нихуя не из чего начинать! Поэтому результат заворачивают в
Optional— типа, может что-то есть, а может и нет, мудак.Optional<Integer> product = numbers.stream() .reduce((a, b) -> a * b); // Optional[24]Работает так же, только первый шаг:
a = 1(первый элемент),b = 2(второй). Перемножили — 2. Дальшеa = 2,b = 3— 6. Ну иa = 6,b = 4— 24, ядрёна вошь!
На что обратить внимание, чтобы не обосраться:
- Зачем это надо: Суммы, произведения, максимумы, конкатенация строк — везде, где надо всё схлопнуть в одно значение.
- Параллельные потоки — головная боль: Если юзаешь параллельный стрим, твой
accumulatorдолжен быть ассоциативным (чтобы не важно было, в каком порядке складывать:(a + b) + cдолжно равнятьсяa + (b + c)). Аidentityдолжен быть нейтральным элементом (например, 0 для сложения, 1 для умножения). Иначе получишь пиздец, а не результат. - Не выёбывайся: Для частых операций вроде
sum(),max(),min()уже есть готовые методы — юзай их, не изобретай велосипед, ёпта.