Domínio da API de Collectors no Java Stream

Introdução ao Collectors

O Collectors é uma classe utilitária da API de Stream Java que fornece várias operações de redução, como acumulação de elementos em coleções, resumo de elementos de acordo com vários critérios e outras operações semelhantes.

Considere um cenário onde precisamos categorizar uma lista de objetos com base em uma propriedade. Por exemplo, separar produtos por sua cor.

package com.example.streams;

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

public class CollectorBasico { public static void main(String[] args) { List<Produto> produtos = Arrays.asList( new Produto("verde", 150), new Produto("amarelo", 120), new Produto("verde", 170), new Produto("amarelo", 125) );

    // Filtrar e coletar em uma nova lista
    List<Produto> produtosVerdes = produtos.stream()
        .filter(p -> p.cor().equals("verde"))
        .collect(Collectors.toList());

    // Agrupamento usando Collectors.groupingBy
    Map<String, List<Produto>> produtosPorCor = produtos.stream()
        .collect(Collectors.groupingBy(Produto::cor));

    System.out.println("Produtos verdes: " + produtosVerdes);
    System.out.println("Agrupados por cor: " + produtosPorCor);
}

}

record Produto(String cor, int peso) {}


</div>Principais Métodos de Coleta
----------------------------

A classe `Collectors` oferece métodos estáticos para diversas operações de coleta. Vamos explorar os mais comuns.

### Cálculos Estatísticos

Podemos calcular médias, somas e estatísticas reusmidas diretamente no stream.

<div class="code-example">```

package com.example.streams;

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

public class EstatisticasCollector {
    public static void main(String[] args) {
        List<Prato> cardapio = Arrays.asList(
            new Prato("carne", false, 800),
            new Prato("peixe", false, 400),
            new Prato("salada", true, 150),
            new Prato("macarrão", true, 550)
        );

        // Média de calorias
        double mediaCalorias = cardapio.stream()
            .collect(Collectors.averagingInt(Prato::calorias));

        // Contagem de itens
        long totalItens = cardapio.stream()
            .collect(Collectors.counting());

        // Estatísticas completas
        IntSummaryStatistics stats = cardapio.stream()
            .collect(Collectors.summarizingInt(Prato::calorias));

        System.out.println("Média de calorias: " + mediaCalorias);
        System.out.println("Total de itens: " + totalItens);
        System.out.println("Resumo estatístico: " + stats);
    }
}

record Prato(String nome, boolean vegetariano, int calorias) {}

Além do groupingBy simples, podemos combinar múltiplos collectors para operações complexas.

package com.example.streams;

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

public class AgrupamentoAvancado { public static void main(String[] args) { List<Prato> cardapio = Arrays.asList( new Prato("carne", false, 800), new Prato("peixe", false, 400), new Prato("salada", true, 150), new Prato("macarrão", true, 550) );

    // Agrupar por vegetarianismo e contar itens
    Map<Boolean, Long> contagemVegetarianos = cardapio.stream()
        .collect(Collectors.partitioningBy(
            Prato::vegetariano,
            Collectors.counting()
        ));

    // Agrupar por tipo e calcular média calórica
    Map<String, Double> mediaCaloriasPorTipo = cardapio.stream()
        .collect(Collectors.groupingBy(
            p -> p.vegetariano() ? "Vegetariano" : "Não-vegetariano",
            Collectors.averagingInt(Prato::calorias)
        ));

    System.out.println("Contagem vegetarianos: " + contagemVegetarianos);
    System.out.println("Média por tipo: " + mediaCaloriasPorTipo);
}

}


</div>### Manipulação de Strings e Coleções

Operações de concatenação e transformação de coleções são simplificadas com os collectors.

<div class="code-example">```

package com.example.streams;

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

public class TransformacaoCollector {
    public static void main(String[] args) {
        List<String> nomes = Arrays.asList("Ana", "Bruno", "Carlos", "Diana");

        // Concatenar strings com delimitador
        String nomesConcatenados = nomes.stream()
            .collect(Collectors.joining(", ", "[", "]"));

        // Converter para conjunto
        Set<String> conjuntoNomes = nomes.stream()
            .collect(Collectors.toSet());

        // Mapear para nova estrutura usando mapping
        String iniciais = nomes.stream()
            .collect(Collectors.mapping(
                nome -> String.valueOf(nome.charAt(0)),
                Collectors.joining("", "Iniciais: ", "")
            ));

        System.out.println("Nomes concatenados: " + nomesConcatenados);
        System.out.println("Conjunto: " + conjuntoNomes);
        System.out.println(iniciais);
    }
}

Podemos direcionar a coleta para impleemntações específicas de coleções.

package com.example.streams;

import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors;

public class ColecoesEspecificas { public static void main(String[] args) { List<Integer> numeros = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);

    // Coletar em LinkedList
    LinkedList<Integer> listaEncadeada = numeros.stream()
        .filter(n -> n % 2 == 0)
        .collect(Collectors.toCollection(LinkedList::new));

    // Criar mapa concorrente
    ConcurrentHashMap<String, Integer> mapaConcorrente = numeros.stream()
        .collect(Collectors.toConcurrentMap(
            n -> "chave_" + n,
            n -> n * 10,
            (v1, v2) -> v1 + v2
        ));

    // Usar reducing para operações personalizadas
    int somaTotal = numeros.stream()
        .collect(Collectors.reducing(0, Integer::sum));

    System.out.println("Lista encadeada: " + listaEncadeada);
    System.out.println("Mapa concorrente: " + mapaConcorrente);
    System.out.println("Soma total: " + somaTotal);
}

}


</div>A flexibilidade da API de Collectors permite construir operações complexas de processamento de dados de maneira decalrativa e concisa, aproveitando todo o poder do framework de Stream do Java.

Tags: java Stream API Collectors groupingBy partitioningBy

Publicado em 7-24 11:32