# Java Collect(): como utilizar operações de redução

Os Stream Collectors são uma poderosa funcionalidade da **API Java 8 Stream** que permite recolher e processar dados de forma eficiente. Explicamos a estrutura e as possíveis utilizações do método Java Collect.

## Quais são os âmbitos de aplicação do Java Collect()?

Um Stream Collector pode ser utilizado para criar uma lista, um conjunto ou um mapa a partir de um fluxo (stream). Um fluxo é uma sequência de elementos que são processados um após o outro. A interface do Collector fornece uma série de **operações de redução** para os dados num fluxo de canalização. Estas são operações finais que recolhem e fundem os resultados das etapas intermédias.

Os coletores podem ser usados, por exemplo, para filtrar ou classificar objetos de um fluxo. Também é possível realizar **agregações**, como somar números, concatenar cadeias ou contar elementos. Além disso, os coletores dispõem de funções para transformar o conteúdo de um fluxo numa estrutura determinada. Dessa forma, por exemplo, é possível converter uma lista num mapa. Os agrupamentos ajudam a categorizar os elementos com determinadas propriedades ou condições. No entanto, a maior vantagem dos coletores de fluxo é que eles permitem processar dados em paralelo usando múltiplas threads (linhas). Isso permite que as operações, especialmente com grandes quantidades de dados, sejam realizadas de forma mais rápida e eficiente.

## A sintaxe do Java Collect()

Este método recebe como argumento um coletor que indica como recolher e agregar os elementos do fluxo. Um coletor é uma interface que oferece diferentes métodos para agrupar os elementos do fluxo de uma forma específica, como uma lista, um conjunto ou um mapa.

Existem dois métodos no Java Collect:

1. R collect(Fornecedor&lt;R&gt; fornecedor, BiConsumer&lt;R, ? super T&gt; acumulador, BiConsumer&lt;R, R&gt; combinador)
2. &lt;R, A&gt; R collect(Collector&lt;? super T, A, R&gt; collector)

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

- **supplier**: cria um contentor que é utilizado para os resultados intermédios.
- **acumulador**: calcula o resultado final.
- **combiner**: combina os resultados de operações de fluxo paralelas.

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

A segunda variante recebe um coletor como argumento e retorna o resultado.

- **R**: o tipo do resultado
- **T**: o tipo dos elementos do fluxo
- **A**: o tipo do acumulador que armazena o estado intermédio da operação do coletor
- **coletor**: realiza a operação de redução.

Com esta variante, os programadores têm a possibilidade de criar **coletores personalizados** que se ajustam especificamente às suas necessidades, proporcionando assim maior flexibilidade e controlo ao processo de redução.

## Exemplos práticos do uso do Java Collect()

A seguir, apresentamos várias funções do método `Stream.collect()` para ilustrar a sua utilização. É recomendável que esteja familiarizado com os operadores Java antes de se aprofundar na **estrutura de coleções**.

### Concatene uma lista de cadeias

Com Java Collect(), pode **concatenar** uma lista de cadeias para obter uma nova cadeia:

```Java
List<String> letters = List.of("a", "b", "c", "d", "e");
// without combiner function
StringBuilder result = letters.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append(",").append(b));
System.out.println(result.toString());
// with combiner function
StringBuilder result1 = letters.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
    (a, b) -> a.append(",").append(b));
System.out.println(result1.toString());
```

Obtemos este resultado:

```Java
abcde
a, b, c, d, e
```

No primeiro cálculo, existe apenas uma instância StringBuilder e nenhuma função combinadora foi utilizada. Portanto, o resultado é `abcde`.

No segundo resultado, vemos que a função combinadora fundiu as instâncias StringBuilder e as separou com uma vírgula.

### Recolher os elementos de uma lista com toList()

Podemos selecionar determinados elementos de uma lista com a função `filter()` e armazená-los numa nova lista com `toList()`.

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

A nova lista agora contém apenas números ímpares:

```Java
[1, 3, 5, 7]
```

### Recolher os elementos de um conjunto com toSet()

Da mesma forma, podemos criar um novo conjunto (set) a partir dos elementos selecionados. A ordem num conjunto pode ser **não ordenada**.

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

Isso nos dá este resultado:

```Java
[2, 4, 6]
```

### Recolher elementos num mapa com toMap()

Um mapa em conjunto com `Collect()` de Java atribui um valor a cada chave.

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

No resultado, vemos que a entrada formada por números pares foi atribuída aos seus valores idênticos:

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

### Combinar elementos de uma cadeia com joining()

O método `joining()` adiciona cada elemento do fluxo na ordem em que aparecem e utiliza um **separador para separar os elementos**. O separador é passado como argumento para `joining()`. Se nenhum separador for especificado, `joining()` utiliza a cadeia vazia `""`.

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

Os resultados são os seguintes:

```Java
result1 ==> "abc"
result2 ==> "{a,b,c}"
```


This is a markdown version of: [https://www.ionos.com/pt-pt/digitalguide/paginas-web/desenvolvimento-web/java-stream-collect/](https://www.ionos.com/pt-pt/digitalguide/paginas-web/desenvolvimento-web/java-stream-collect/) for AI/LLM consumption.