saverioriotto.it

Java Stream API: funzioni comunemente utilizzate con esempi

L'API Java Stream fornisce una varietà di funzioni comunemente utilizzate per la manipolazione e l'elaborazione dei dati. Vediamo quelli comunemente utilizzati con esempi pratici.

Java Stream API: funzioni comunemente utilizzate con esempi

L'API Java Stream è una parte fondamentale del pacchetto java.util.stream introdotto in Java 8. Questa API offre una potente e flessibile astrazione per eseguire operazioni di elaborazione dei dati su sequenze di elementi, come collezioni, array o altre fonti di dati.

Le principali caratteristiche dell'API Java Stream includono:

Pipeline di Operazioni: Con Java Stream, è possibile creare una sequenza di operazioni su un flusso di dati. Queste operazioni possono includere filtraggio, mappatura, ordinamento, raggruppamento e altro. Le operazioni vengono eseguite in una sequenza logica, formando una "pipeline" di operazioni.

Lazy Evaluation: Un aspetto chiave della Stream API è l'evaluation lazy. Ciò significa che le operazioni sulla pipeline non vengono eseguite immediatamente al momento della loro definizione, ma vengono posticipate fino a quando il risultato finale è effettivamente richiesto. Questo può migliorare l'efficienza e ridurre la complessità computazionale.

Parallelismo Semplificato: La Stream API semplifica l'esecuzione parallela di operazioni su flussi di dati. È possibile sfruttare facilmente i processori multi-core per ottenere prestazioni migliori in caso di grandi quantità di dati.

Interoperabilità con le Collezioni: Le Stream API possono essere utilizzate con collezioni Java esistenti, come liste, insiemi e mappe. È possibile convertire facilmente una collezione in uno stream o viceversa.

Operazioni Terminali: Una pipeline Stream deve terminare con un'operazione terminale, come forEach, collect, reduce, o count, per ottenere un risultato concreto. Queste operazioni generano un risultato o un effetto collaterale.

In questo articolo, esploreremo alcune delle funzioni comunemente utilizzate all'interno di questa API, fornendo esempi pratici per illustrare come siano applicate.

Esempi utili

Filtro in base a una determinata condizione definita dal predicato:

filter(Predicate predicate)

List numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List evenNumbers = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .collect(Collectors.toList()); 
// Result: [2, 4, 6]

Trasforma ogni elemento di uno stream da un tipo T a un tipo R utilizzando una funzione di mappatura fornita:

map(Function<T, R> mapper)

List names = Arrays.asList("Alice", "Bob", "Charlie");
List nameLengths = names.stream()
                                 .map(String::length)
                                 .collect(Collectors.toList()); 
// Result: [5, 3, 7]

Trasforma gli elemento in uno stream piu complesso in uno stream separato e "appiattisce" tutti questi sotto-stream in un singolo stream:

flatMap(Function<T, Stream> mapper)

List nestedLists = Arrays.asList(
    Arrays.asList(1, 2),
    Arrays.asList(3, 4, 5),
    Arrays.asList(6)
);
List flattenedList = nestedLists.stream()
                                        .flatMap(List::stream)
                                        .collect(Collectors.toList()); 
// Result: [1, 2, 3, 4, 5, 6]

Raccoglie gli elementi dello stream in una collezione o in un'altra struttura dati definita dal Collector:

collect(Collector<T, A, R> collector)

List words = Arrays.asList("Hello", "Stream", "API");
String concatenated = words.stream()
                           .collect(Collectors.joining(" ")); 
// Result: "Hello Stream API"

Esegui un'azione su ciascun elemento dello stream:

forEach(Consumer action)

List numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.stream()
       .forEach(num -> System.out.print(num + " ")); 
// Output: 1 2 3 4 5

Combina gli elementi dello stream utilizzando l'operatore binario specificato e un valore di identità iniziale:

reduce(T identity, BinaryOperator accumulator)

List numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
                 .reduce(0, (a, b) -> a + b); 
// Result: 15

Ordina gli elementi dello stream in ordine naturale o utilizzando un comparatore:

sorted() or sorted(Comparator comparator)

List names = Arrays.asList("Alice", "Bob", "Charlie");
List sortedNames = names.stream()
                               .sorted()
                               .collect(Collectors.toList()); 
// Result: ["Alice", "Bob", "Charlie"]

Rimuove gli elementi duplicati dallo stream:

distinct()

List numbers = Arrays.asList(1, 2, 2, 3, 3, 4, 5);
List distinctNumbers = numbers.stream()
                                       .distinct()
                                       .collect(Collectors.toList()); 
// Result: [1, 2, 3, 4, 5]

Restituisce il numero di elementi nello stream:

count()

List names = Arrays.asList("Alice", "Bob", "Charlie");
long count = names.stream()
                  .count(); // Result: 3

Trova il massimo e minimo tra gli elementi dello stream in base al comparatore specificato:

max(Comparator comparator) and min(Comparator comparator)

List numbers = Arrays.asList(5, 2, 8, 3, 1);
Optional max = numbers.stream()
                              .max(Integer::compareTo); 
// Result: Optional[8]

Verifica se alcuni(any), tutti(all) o nessuno(none) degli elementi soddisfano una determinata condizione:

anyMatch(Predicate predicate), allMatch(Predicate predicate), and noneMatch(Predicate predicate)

List numbers = Arrays.asList(1, 2, 3, 4, 5);
boolean anyEven = numbers.stream().anyMatch(n -> n % 2 == 0);    // true
boolean allEven = numbers.stream().allMatch(n -> n % 2 == 0);    // false
boolean noneOdd = numbers.stream().noneMatch(n -> n % 2 != 0);   // false

Recupera il primo elemento o un qualsiasi elemento dallo stream:

findFirst() and findAny()

List numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional firstEven = numbers.stream()
                                     .filter(n -> n % 2 == 0)
                                     .findFirst(); 
// Result: Optional[2]
Optional anyEven = numbers.stream()
                                   .filter(n -> n % 2 == 0)
                                   .findAny();   
// Result: Optional[2] (or any other even number)

Limita la dimensione dello stream o salta uno specificato numero di elementi:

limit(long maxSize) and skip(long n)

List numbers = Arrays.asList(1, 2, 3, 4, 5);
List limited = numbers.stream()
                              .limit(3)
                              .collect(Collectors.toList()); 
// Result: [1, 2, 3]

List skipped = numbers.stream()
                               .skip(2)
                               .collect(Collectors.toList()); 
// Result: [3, 4, 5]

Raggruppa gli elementi dello stream in una mappa basata sulla funzione di classificazione:

groupBy(Function<T, K> classifier)

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

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

public class GroupByExample {
    public static void main(String[] args) {
        List people = Arrays.asList(
            new Person("Alice", 25),
            new Person("Bob", 30),
            new Person("Charlie", 25),
            new Person("David", 30)
        );

        Map<Integer, List> peopleByAge = people.stream()
            .collect(Collectors.groupingBy(Person::getAge));

        System.out.println(peopleByAge);
//Result {25=[Person{name='Alice', age=25}, Person{name='Charlie', age=25}],
 //30=[Person{name='Bob', age=30}, Person{name='David', age=30}]} 
    }
}

Partiziona gli elementi dello stream in due gruppi basati su un dato predicato:

partitionBy(Predicate predicate)

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

public class PartitionByExample {
    public static void main(String[] args) {
        List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        Map<Boolean, List> evenAndOdd = numbers.stream()
            .collect(Collectors.partitioningBy(n -> n % 2 == 0));

        System.out.println("Even numbers: " + evenAndOdd.get(true));
        //Result Even numbers: [2, 4, 6, 8, 10]
        System.out.println("Odd numbers: " + evenAndOdd.get(false));
        //Result Odd numbers: [1, 3, 5, 7, 9]
    }
}

Conversione dello stream in un array:

toArray()

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

public class ToArrayExample {
    public static void main(String[] args) {
        List colors = Arrays.asList("Red", "Green", "Blue");

        String[] colorArray = colors.stream()
            .toArray(String[]::new);

        System.out.println(Arrays.toString(colorArray));
      //Result [Red, Green, Blue]
    }
}

Conclusione

Queste sono solo alcune delle funzioni fondamentali offerte dalla Java Stream API. Queste funzioni rendono più semplice e concisa l'elaborazione dei dati in Java, consentendo di scrivere codice più leggibile ed efficiente.




Commenti
* Obbligatorio