Desafio Java

Processamento de transações com streams

Enunciado

Dada uma lista de transações (cada uma com id, tipo e valor), use streams para:

  1. Filtrar transações do tipo "CREDITO".
  2. Agrupar por id usando Collectors.groupingBy.
  3. Para cada grupo, somar os valores usando Collectors.summingDouble.
  4. Imprimir o mapa resultante (id -> soma).

Considere a classe Transacao já definida.

Requisitos

  • Use filter para manter apenas transações do tipo "CREDITO".
  • Use Collectors.groupingBy com Transacao::getId como classificador.
  • Use Collectors.summingDouble como coletor downstream.
  • Imprima o mapa ordenado por id (use TreeMap).

Código inicial

import java.util.*;
import java.util.stream.*;

class Transacao {
    private final int id;
    private final String tipo;
    private final double valor;
    public Transacao(int id, String tipo, double valor) {
        this.id = id;
        this.tipo = tipo;
        this.valor = valor;
    }
    public int getId() { return id; }
    public String getTipo() { return tipo; }
    public double getValor() { return valor; }
}

public class ExercicioDesafio {
    public static void main(String[] args) {
        List<Transacao> transacoes = Arrays.asList(
            new Transacao(1, "CREDITO", 100.0),
            new Transacao(2, "DEBITO", 50.0),
            new Transacao(1, "CREDITO", 200.0),
            new Transacao(3, "CREDITO", 300.0),
            new Transacao(2, "CREDITO", 150.0)
        );
        // Complete aqui
    }
}

Saída esperada

{1=300.0, 2=150.0, 3=300.0}
Ver dica

Use Collectors.groupingBy(Transacao::getId, TreeMap::new, Collectors.summingDouble(Transacao::getValor)).

Mostrar solução
import java.util.*;
import java.util.stream.*;

class Transacao {
    private final int id;
    private final String tipo;
    private final double valor;
    public Transacao(int id, String tipo, double valor) {
        this.id = id;
        this.tipo = tipo;
        this.valor = valor;
    }
    public int getId() { return id; }
    public String getTipo() { return tipo; }
    public double getValor() { return valor; }
}

public class ExercicioDesafio {
    public static void main(String[] args) {
        List<Transacao> transacoes = Arrays.asList(
            new Transacao(1, "CREDITO", 100.0),
            new Transacao(2, "DEBITO", 50.0),
            new Transacao(1, "CREDITO", 200.0),
            new Transacao(3, "CREDITO", 300.0),
            new Transacao(2, "CREDITO", 150.0)
        );

        Map<Integer, Double> somaPorId = transacoes.stream()
                .filter(t -> "CREDITO".equals(t.getTipo()))          // apenas créditos
                .collect(Collectors.groupingBy(
                        Transacao::getId,                             // agrupa por id
                        TreeMap::new,                                 // mapa ordenado
                        Collectors.summingDouble(Transacao::getValor) // soma os valores
                ));

        System.out.println(somaPorId);
    }
}

Passo a passo

  1. Criamos uma lista de transações com id, tipo e valor.
  2. transacoes.stream() cria um stream.
  3. filter(t -> "CREDITO".equals(t.getTipo())) mantém apenas transações do tipo "CREDITO".
  4. collect(Collectors.groupingBy(...)) agrupa as transações filtradas.
  5. O primeiro argumento de groupingBy é Transacao::getId, que extrai o id como chave.
  6. O segundo argumento TreeMap::new especifica que o mapa resultante será um TreeMap, garantindo ordenação pelas chaves.
  7. O terceiro argumento Collectors.summingDouble(Transacao::getValor) é o coletor downstream que soma os valores de cada grupo.
  8. O resultado é impresso.

Por que funciona

A combinação de filter com groupingBy e um coletor downstream permite processar e agregar dados em uma única passagem. O stream é preguiçoso, então as operações só são executadas quando collect é chamado. O uso de TreeMap garante que as chaves (ids) estejam ordenadas, o que é útil para apresentação.

Erros comuns

  • Esquecer de importar java.util.stream.Collectors.
  • Usar Collectors.summingInt ou summingLong quando os valores são double, causando erro de compilação.
  • Não fornecer o terceiro argumento para groupingBy e depois tentar usar TreeMap, resultando em um HashMap não ordenado.
  • Filtrar após agrupar: isso não funcionaria corretamente porque o agrupamento já teria incluído todos os tipos.

Outra forma de resolver

Se não precisar de ordenação, omita o TreeMap:

Map<Integer, Double> somaPorId = transacoes.stream()
        .filter(t -> "CREDITO".equals(t.getTipo()))
        .collect(Collectors.groupingBy(Transacao::getId, Collectors.summingDouble(Transacao::getValor)));

Isso é mais simples, mas a ordem das chaves não é garantida.

Saída esperada

{1=300.0, 2=150.0, 3=300.0}