< Home
Stampa

Stream

Sommario

La libreria Stream di Java (introdotta con Java 8) introduce elementi di programmazione funzionale in Java.

La libreria introduce le seguenti funzionalità:

  • è possibile creare pipeline di elaborazione. Una pipeline è un insieme di elaborazioni in sequenza su una lista di elementi. Ciascuna elaborazione della pipeline è indipendente dalle altre: ricev
  • l’esecuzione è lazy, si attiva solo quando si chiude la pipeline.
  • è possibile usare la programmazione parallela, senza gestirla direttamente

Qui useremo nella sua versione generica Stream<T>.

Generare uno stream

String[] arrayOfStrings = new String[]{"a","b","c"};
Stream<String> streamFromArray = Arrays.stream(arrayOfStrings);
List<String> list = List.of("Rosso", "Blu", "Verde");
Stream<String> streamFromList = list.stream();
Stream<String> streamFromOf = Stream.of("Giallo", "Nero", "Bianco");                        Stream<Integer> evenStream = Stream.iterate(2, n -> n+2).limit(10);
Stream<String> stringStream = Pattern.compile(",").splitAsStream("bianco,rosso,verdone");

E’ quindi possibile generare Stream da array, liste, direttamente con of, o nel caso delle stringhe, da una espressione regolare (in questo caso lo split di una stringa).

Intermediate operation

Le operazioni intermedie generano un nuovo stream dal precedente. Di particolare importanza filter, map e sorted.

streamFromArray = streamFromArray.distinct();
streamFromArray = streamFromArray.sorted();
randomStream = randomStream.filter(e -> e % 2 == 0);
Stream<Integer> oddStream = evenStream.map(e -> e + 1);

Terminal operation

L’operazione terminale genera un output dallo stream. La collect prende come argomento un metodo statico dalla classe Collectors. Molto utile la reduce quando si vuole calcolare un risultato dagli elementi di una lista.

Boolean found = evenStream.anyMatch(e -> e % 2 == 0);
Long count = stringStream.count();
List<String> arrayList = streamFromArray.collect(Collectors.toList());
String joinList = streamFromList.collect(Collectors.joining("-"));
Integer reduced = evenStream.reduce(0, (a,e) -> a+e);
Optional<Double> max = randomStream.max(Double::compareTo);
Optional<Double> min = randomStream.min(Double::compareTo);        
Optional<Double> first = randomStream.findFirst();

Pipeline

Gli stream come visto sopra sono molto comodi perché eliminano la necessità di eseguire cicli for su ogni elemento della lista, ma applicano automaticamente la funzione passata come argomento a tutti gli elementi, evitando molto codice.

Vediamo qualche esempio:

private static Integer sum(List<Integer> list) {
  return list.stream().reduce(0, (acc, value) -> acc+value);
}

Vediamo un esempio più strutturato:

public record Persona(String nome, String cognome, int eta, String sesso) {}

    
    public static void main(String[] args) {
        List<Persona> persone = List.of(
            new Persona("Luca", "Rossi", 28, "M"),
            new Persona("Maria", "Bianchi", 34, "F"),
            new Persona("Giovanni", "Verdi", 45, "M"),
            new Persona("Anna", "Russo", 22, "F"),
            new Persona("Paolo", "Ferrari", 51, "M"),
            new Persona("Giulia", "Esposito", 29, "F"),
            new Persona("Marco", "Romano", 38, "M"),
            new Persona("Chiara", "Gallo", 26, "F"),
            new Persona("Stefano", "Costa", 42, "M"),
            new Persona("Valentina", "Conti", 31, "F")
        );

        List<Persona> fU30 = persone.stream()
            .filter(p -> p.sesso=="F")
            .filter(p -> p.eta < 30)
            .toList();

        int etamedia = persone.stream()
            .map(Persona::eta)
            .reduce(0, (a,eta) -> a + eta) / persone.size();

    }