Como usar Java collect() para coletar e processar dados

Stream Collectors são um recurso poderoso da API Java 8 Stream, capaz de coletar e processar dados de maneira eficiente. Conheça sua estrutura e como o método Java collect() pode ser utilizado.

Como usar Java collect()?

Um Stream Collector pode ser usado para criar uma lista, um conjunto ou um mapa a partir de um stream. Um stream, por sua vez, é uma sequência de elementos processados um após o outro. A interface Collector oferece um conjunto de operações de redução para dados em um pipeline de stream, ou seja, operações terminais que coletam e mesclam resultados de etapas intermediárias.

Collectors podem ser usados para filtrar ou ordenar objetos de um stream. Agregações também são possíveis, como somar números, combinar strings ou contar elementos. Além disso, Collectors possuem funções que podem transformar o conteúdo de um stream em uma estrutura específica. Você pode, por exemplo, transformar uma lista em um mapa. Ainda, agrupamentos ajudam a categorizar elementos com certas propriedades ou condições.

O mais importante é que Stream Collectors têm a vantagem de processar dados simultaneamente, usando vários threads. Isso permite que operações sejam realizadas muito mais rapidamente e de forma eficiente, especialmente em grandes quantidades de dados.

Qual é a sintaxe do Java collect()?

O método aceita um Collector como argumento, que descreve como os elementos do stream devem ser coletados e agregados. Collector é uma interface que fornece vários métodos para agregar elementos do stream de uma forma específica, como em uma lista, um conjunto ou um mapa.

Existem duas variantes do método Java Stream collect():

  1. <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator, BiConsumer<R, R> combiner)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

A primeira variante tem três funções como argumentos:

  • supplier: Cria um recipiente que será usado para resultados intermediários.
  • accumulator: Calcula o resultado final.
  • combiner: Combina os resultados de operações de stream paralelos.

Esses Collectors predefinidos já estão incluídos na biblioteca padrão e podem ser facilmente importados e usados.

A segunda variante aceita um Collector como argumento e retorna um resultado:

  • R: O tipo de resultado.
  • T: O tipo de elementos no stream.
  • A: O tipo de acumulador que armazena o estado intermediário da operação do collector.
  • collector: Executa a operação de redução.

Usando essa variante, os desenvolvedores podem criar Collectors personalizados, que são especificamente adaptados às suas necessidades, proporcionando maior flexibilidade e controle sobre o processo de redução.

Exemplos práticos do uso do Java collect()

Abaixo, ilustramos várias funções do método Stream.collect(). Você deve se familiarizar com os operadores em Java básicos antes de se aprofundar no framework de coleção.

Concatenar lista de strings

Com Java collect(), podemos concatenar uma lista de strings para obtermos uma nova string:

List<String> letras = List.of("a", "b", "c", "d", "e");
// sem função combiner
StringBuilder resultado = letras.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append("").append(b));
System.out.println(resultado.toString());
// com função combiner
StringBuilder resultado1 = letras.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append("").append(b));
System.out.println(resultado1.toString());
Java

A saída é:

abcde
a b c d e
Java

No primeiro cálculo, foi usada apenas uma instância de StringBuilder e nenhuma função combiner. Justamente por isso que o resultado exibido foi abcde.

Na segunda saída, a função combiner mesclou as instâncias de StringBuilder e as separou por vírgula.

Coletar elementos em uma lista com toList()

Podemos usar a função filter() para selecionar certos elementos de uma lista e, em seguida, usar toList() para armazená-los em uma nova lista.

List<Integer> numeros = List.of(1, 2, 3, 4, 5, 6, 7);
List<Integer> numerosImpares = numeros.stream().filter(x -> x % 2 != 0).collect(Collectors.toList());
System.out.println(numerosImpares);
Java

A nova lista tem apenas números ímpares:

[1, 3, 5, 7]
Java

Coletar elementos em um conjunto com toSet()

Da mesma forma, podemos selecionar elementos para criar um novo conjunto a partir deles. Elementos em um conjunto não precisam ser dispostos em uma ordem específica.

List<Integer> numeros = List.of(1, 2, 3, 4, 5, 6, 7);
Set<Integer> numerosPares = numeros.parallelStream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
System.out.println(numerosPares);
Java

O código exibe a seguinte saída:

[2, 4, 6]
Java

Coletar elementos em um mapa com toMap()

Um mapa pode ser usado juntamente com o Java collect() para atribuir um valor a cada chave.

List<Integer> numeros = List.of(1, 2, 3, 4, 5, 6, 7);
Map<Integer, String> mapaNumerosPares = numeros.parallelStream().filter(x -> x % 2 == 0)
    .collect(Collectors.toMap(Function.identity(), x -> String.valueOf(x)));
System.out.println(mapaNumerosPares);
Java

Na saída, podemos observar que cada número par de entrada foi atribuído a um valor idêntico:

{2=2, 4=4, 6=6}
Java

Combinar elementos em uma string com joining()

O método joining() combina elementos de um stream na ordem em que aparecem, usando um separador para separar os elementos. O separador é passado como argumento para joining(). Se nenhum separador for especificado, joining() usará a string vazia "".

jshell> String resultado1 = Stream.of("a", "b", "c").collect(Collectors.joining());
jshell> String resultado2 = Stream.of("a", "b", "c").collect(Collectors.joining("", "{", "}"));
Java

Os resultados obtidos são:

resultado1 ==> "abc"
resultado2 ==> "{abc}"
Java
Este artigo foi útil?
Para melhorar a sua experiência, este site usa cookies. Ao acessar o nosso site, você concorda com nosso uso de cookies. Mais informações
Page top