# Java Collect(): come utilizzare le operazioni di riduzione

Gli Stream Collector sono una potente funzionalità dell’**API Stream di Java 8**, che permette di raccogliere ed elaborare i dati in modo efficiente. Ti spieghiamo la struttura e le possibilità di applicazione del metodo `collect` in Java.

## Quali sono i campi di applicazione per Java Collect()?

Uno Stream Collector può essere utilizzato per creare una lista, un set o una mappa partendo da uno stream. Una mappa è una sequenza di elementi che vengono elaborati uno dopo l’altro. L’interfaccia Collector offre una serie di **operazioni di riduzione** per i dati in una pipeline di stream. Si tratta di operazioni da terminale che raccolgono e uniscono i risultati di passaggi intermedi.

Ad esempio, i Collector possono essere utilizzati per filtrare o ordinare gli oggetti di uno stream. È possibile eseguire anche l’operazione di **aggregazione**, ossia la somma di numeri, l’unione di stringhe o il conteggio di elementi. Inoltre, i Collector dispongono di funzioni per trasformare i contenuti di uno stream in una data struttura. In questo modo è possibile, ad esempio, convertire una lista in una mappa. I raggruppamenti aiutano a categorizzare gli elementi con determinate caratteristiche o condizioni. Ma, soprattutto, gli Stream Collector hanno il vantaggio di **elaborare i dati in parallelo per mezzo di più thread**. In questo modo permettono di eseguire le operazioni molto più velocemente e con molta più efficienza, in particolare in presenza di grandi quantità di dati.

## La sintassi di Java Collect()

Questo metodo accetta un Collector come argomento che descrive il modo in cui gli elementi dello stream devono essere raccolti e aggregati. Un **Collector è un’interfaccia** che mette a disposizione diversi metodi per unire gli elementi dello stream in un data forma, ad esempio in una lista, un set o una mappa.

Esistono due tipi di metodi Java Collect:

1. &lt;R&gt; R collect(Supplier&lt;R&gt; supplier, BiConsumer&lt;R, ? super T&gt; accumulator,BiConsumer&lt;R, R&gt; combiner)
2. &lt;R, A&gt; R collect(Collector&lt;? super T, A, R&gt; collector)

La prima variante ha tre funzioni come argomento:

- **supplier**: crea un contenitore utilizzato per i risultati intermedi.
- **accumulator**: calcola il risultato finale.
- **combiner**: combina i risultati di operazioni di stream parallele.

Questi Collector predefiniti sono già inclusi nella libreria standard e possono essere importati e utilizzati facilmente.

La seconda variante utilizza come argomento un Collector e restituisce il risultato.

- **R**: il tipo di risultato.
- **T**: il tipo degli elementi nello stream.
- **A**: il tipo dell’accumulatore che memorizza lo stato intermedio dell’operazione Collector.
- **collector**: esegue l’operazione di riduzione.

Utilizzando questa variante, gli sviluppatori possono creare **Collector su misura** pensati appositamente per le loro esigenze, offrendo maggiore flessibilità e controllo sul processo di riduzione.

## Esempi pratici di utilizzo di Java Collect()

Nelle parti seguenti ti mostriamo diverse funzioni del metodo `Stream.collect()`. Prima di iniziare a usare il **Collection Framework**, ti consigliamo di prendere dimestichezza con gli [operatori Java](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/operatori-java/).

### Concatenazione di una lista di stringhe

Con Java Collect() puoi **concatenare** una lista di stringhe per ottenere una nuova stringa:

```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());
```

Il risultato che otteniamo è il seguente:

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

Con il primo calcolo è presente soltanto un’istanza `StringBuilder` e non è stata utilizzata alcuna funzione `Combiner`. Per questo motivo il risultato è `abcde`.

Il secondo output mostra come la funzione `Combiner` unisce le istanze `StringBuilder` e le separa con una virgola.

### Raccolta di elementi in una lista con toList()

È possibile utilizzare la funzione `filter()` per selezionare determinati elementi e memorizzarli in una nuova lista con `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);
```

La nuova lista contiene quindi esclusivamente numeri dispari:

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

### Raccolta di elementi in un set con toSet()

Analogamente è possibile creare un nuovo set partendo da elementi selezionati. La sequenza può essere **non ordinata** in un set.

```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);
```

Il risultato è il seguente:

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

### Raccolta di elementi in una mappa con toMap()

L’uso di una mappa in combinazione con Java Collect() permette di assegnare un valore a ciascuna chiave.

```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);
```

Il risultato mostra come l’input, composto da numeri pari, è stato assegnato ai suoi valori identici:

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

### Combinazione di elementi in una catena di caratteri con joining()

Il metodo `joining()` combina ciascun elemento dello stream nell’ordine in cui appare e utilizza **un carattere separatore per separare gli elementi**. Il separatore può essere passato a `joining()` come argomento. Se non si indica nessun separatore, `joining()` utilizza la stringa vuota `""`.

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

I risultati sono:

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


This is a markdown version of: [https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/java-stream-collect/](https://www.ionos.it/digitalguide/siti-web/programmazione-del-sito-web/java-stream-collect/) for AI/LLM consumption.