Espressioni Lambda e Stream

Tags
Published
Author

1. Espressioni Lambda

Un'espressione lambda è una funzione anonima che consente di scrivere codice funzionale in Java.
Può essere utilizzata per passare il comportamento come argomento a un metodo o per implementare metodi di interfacce funzionali in modo conciso.

Sintassi

La sintassi base di un'espressione lambda è la seguente:
(parametri) -> { corpo }
  • Parametri: Specificano i valori in ingresso. Se c'è un solo parametro, le parentesi possono essere omesse.
  • Freccia (->): Separa i parametri dal corpo della lambda.
  • Corpo: Contiene il codice eseguito dall'espressione lambda.

Esempi

  1. Lambda con un parametro:
    1. Consumer<String> stampa = s -> System.out.println(s); stampa.accept("Hello, Lambda!");
  1. Lambda con più parametri:
    1. BiFunction<Integer, Integer, Integer> somma = (a, b) -> a + b; System.out.println(somma.apply(5, 3)); // Output: 8
  1. Lambda con corpo complesso:
    1. Comparator<Integer> comparatore = (a, b) -> { if (a > b) return 1; else if (a < b) return -1; else return 0; };

Interfacce Funzionali

Un'espressione lambda richiede un'interfaccia funzionale, ossia un'interfaccia con un solo metodo astratto.
  • Runnable (senza ritorno):
    • Runnable runnable = () -> System.out.println("Esecuzione in corso..."); runnable.run();
  • Function<T, R> (un parametro, un valore di ritorno):
    • Function<String, Integer> lunghezza = s -> s.length(); System.out.println(lunghezza.apply("Lambda")); // Output: 6

2. Stream

Le Stream API permettono di elaborare collezioni di dati in modo funzionale e dichiarativo. Con gli stream è possibile filtrare, trasformare, ordinare e ridurre i dati in maniera efficiente.

Creazione di uno Stream

Uno stream può essere creato da diverse sorgenti, come liste, array o file:
import java.util.stream.*; List<String> nomi = Arrays.asList("Anna", "Luca", "Marco"); Stream<String> stream = nomi.stream();

Operazioni su uno Stream

Gli stream supportano due tipi di operazioni:
  1. Operazioni intermedie: Restituiscono uno stream e possono essere concatenate.
  1. Operazioni terminali: Restituiscono un risultato e terminano lo stream.

Operazioni Intermedie

  1. filter(): Filtra elementi in base a una condizione.
    1. List<String> filtrati = nomi.stream() .filter(nome -> nome.startsWith("M")) .collect(Collectors.toList()); System.out.println(filtrati); // Output: [Marco]
  1. map(): Trasforma ogni elemento.
    1. List<Integer> lunghezze = nomi.stream() .map(String::length) .collect(Collectors.toList()); System.out.println(lunghezze); // Output: [4, 4, 5]
  1. sorted(): Ordina gli elementi.
    1. List<String> ordinati = nomi.stream() .sorted() .collect(Collectors.toList()); System.out.println(ordinati); // Output: [Anna, Luca, Marco]
  1. distinct(): Rimuove duplicati.
    1. List<Integer> unici = Arrays.asList(1, 2, 2, 3, 3, 4).stream() .distinct() .collect(Collectors.toList()); System.out.println(unici); // Output: [1, 2, 3, 4]

Operazioni Terminali

  1. collect(): Converte uno stream in una collezione.
    1. List<String> lista = nomi.stream() .collect(Collectors.toList());
  1. forEach(): Itera sugli elementi.
    1. nomi.stream().forEach(System.out::println);
  1. reduce(): Combina gli elementi in un unico risultato.
    1. int somma = Arrays.asList(1, 2, 3, 4).stream() .reduce(0, Integer::sum); System.out.println(somma); // Output: 10
  1. count(): Conta gli elementi.
    1. long conteggio = nomi.stream().count(); System.out.println(conteggio); // Output: 3
  1. anyMatch(), allMatch(), noneMatch(): Testano condizioni sugli elementi.
    1. boolean esisteMarco = nomi.stream().anyMatch(nome -> nome.equals("Marco")); System.out.println(esisteMarco); // Output: true

Back to →
🐚
Java