Atualizado: 21/09/2025

Este conteúdo é original e não foi gerado por inteligência artificial.

O Método reduce na Stream API em Java

O método reduce é a operação de redução mais fundamental e de propósito geral da Stream API. Ele processa todos os elementos de um stream para produzir um único valor como resultado, aplicando repetidamente uma função de combinação.

1. reduce sem Valor de Identidade

A primeira forma do método reduce recebe apenas um acumulador. O resultado é encapsulado em um Optional, porque se o stream estiver vazio, não há um primeiro elemento para iniciar a acumulação e, portanto, nenhum resultado pode ser produzido.

Optional<T> reduce(BinaryOperator<T> accumulator)

O BinaryOperator<T> é uma função que recebe dois elementos e os combina em um. O reduce aplica essa função sequencialmente.

import java.util.Optional;
import java.util.stream.Stream;

Stream<Integer> numbersStream = Stream.of(1, 2, 3, 4, 5, 6);
Optional<Integer> result = numbersStream.reduce((x, y) -> x * y);

result.ifPresent(System.out::println); // Saída: 720

2. reduce com Valor de Identidade

A segunda forma aceita um valor de identidade, o que garante que sempre haverá um resultado, mesmo que o stream esteja vazio. Por isso, o retorno não é um Optional.

T reduce(T identity, BinaryOperator<T> accumulator)
  • T identity: Um valor inicial para a operação. Se o stream for vazio, este é o valor retornado.

Ponto Chave: O Elemento de Identidade

O valor de identidade deve ser um "elemento neutro" para a operação de acumulação. Isso significa que, ao combinar a identidade com qualquer elemento, o resultado é o próprio elemento.

  • Para soma, a identidade é 0 (x + 0 = x).
  • Para multiplicação, a identidade é 1 (x * 1 = x).
  • Para concatenação de strings, a identidade é "" (x + "" = x).
Stream<Integer> numberStream = Stream.of(-4, 3, -2, 1);
int identity = 1; // Identidade para a multiplicação

int result = numberStream.reduce(identity, (x, y) -> x * y);

System.out.println(result);  // Saída: 24

3. reduce com Transformação de Tipo

A terceira forma é a mais versátil, permitindo que o tipo do resultado seja diferente do tipo dos elementos no stream. Ela foi projetada para funcionar de forma eficiente, especialmente em streams paralelos.

<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner)
  • U identity: O valor inicial para o resultado.
  • BiFunction<U, T, U> accumulator: Incorpora um elemento do stream (T) ao resultado parcial (U).
  • BinaryOperator<U> combiner: Combina dois resultados parciais (U). Este combinador é usado apenas em processamento paralelo para unir os resultados calculados por diferentes threads.

Vamos somar os preços de uma lista de telefones que custam menos de 5000.

import java.util.stream.Stream;

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

public class ReduceExample {
    public static void main(String[] args) {
        Stream<Phone> phoneStream = Stream.of(
            new Phone("iPhone 15", 5500),
            new Phone("Pixel 8", 4500),
            new Phone("Samsung Galaxy S24", 4000),
            new Phone("Xiaomi 14", 3200)
        );

        int sum = phoneStream.reduce(
            0, // identity: a soma começa em 0
            (partialSum, phone) -> { // accumulator
                if (phone.getPrice() < 5000) {
                    return partialSum + phone.getPrice();
                }
                return partialSum;
            },
            (partialSum1, partialSum2) -> partialSum1 + partialSum2 // combiner
        );

        System.out.println(sum); // 11700 (4500 + 4000 + 3200)
    }
}

Alternativa Mais Comum e Legível

Embora o reduce seja poderoso, para muitas tarefas comuns, uma combinação de outros métodos é mais clara. A maneira idiomática de resolver o problema anterior seria:

int idiomaticSum = phoneStream.filter(p -> p.getPrice() < 5000) // 1. Filtra
                               .mapToInt(Phone::getPrice)       // 2. Mapeia para int
                               .sum();                           // 3. Usa o método terminal sum()

Esta abordagem é preferível por ser mais legível e compor melhor as operações. Prefira reduce quando a lógica de acumulação é complexa e não pode ser expressa facilmente por uma combinação de map e um método terminal simples.

Resumo

  • reduce(accumulator): Realiza uma redução e retorna um Optional, pois o stream pode ser vazio.
  • reduce(identity, accumulator): Usa um valor inicial (identity), garantindo um resultado. O tipo do resultado é o mesmo dos elementos do stream.
  • reduce(identity, accumulator, combiner): Permite que o resultado seja de um tipo diferente e é projetado para funcionar com streams paralelos, onde o combiner une os resultados parciais.
  • A combinação de filter/map com métodos terminais específicos (sum, count, collect) é frequentemente mais legível e deve ser preferida a reduce para tarefas comuns.
Política de Privacidade

Copyright © www.programicio.com Todos os direitos reservados

É proibida a reprodução do conteúdo desta página sem autorização prévia do autor.

Contato: programicio@gmail.com