La programmazione funzionale in Java ha guadagnato slancio con l'introduzione delle espressioni lambda e delle interfacce funzionali (a partire da Java 8).
Storia della questione
Prima dell'arrivo di Java 8, tutte le interfacce erano insiemi di metodi astratti, e il paradigma era orientato alla OOP. Con l'introduzione delle interfacce funzionali e delle espressioni lambda, è diventato possibile scrivere codice più conciso e seguire i principi della FP, migliorando la leggibilità e l'espressività del codice.
Problema
Il codice relativo alla gestione di eventi, collezioni o logica asincrona stava diventando ridondante: si dovevano creare classi separate o classi anonime interne. Questo complicava la manutenzione e la scalabilità del codice.
Soluzione
Un'interfaccia funzionale è un'interfaccia con esattamente un metodo astratto. Può essere utilizzata come destinazione per un'espressione lambda. Nella libreria standard sono stati introdotti interfacce funzionali tipiche come Function<T, R>, Predicate<T>, Supplier<T>, Consumer<T>, oltre alla possibilità di creare interfacce proprie.
Esempio di codice:
import java.util.function.Function; public class FunctionalExample { public static void main(String[] args) { // Interfaccia funzionale standard Function Function<String, Integer> stringLength = s -> s.length(); System.out.println(stringLength.apply("Java")); // Stampa 4 } }
Caratteristiche chiave:
È possibile dichiarare un'interfaccia funzionale con più metodi astratti, se gli altri metodi hanno implementazioni predefinite o sono statici?
No, un'interfaccia funzionale può contenere solo un metodo astratto. È consentito avere metodi predefiniti (default) o statici.
È possibile ereditare un'interfaccia funzionale da un'altra interfaccia con più metodi astratti?
No, se l'interfaccia risultante ha più di un metodo astratto, smette di essere funzionale e non può essere utilizzata per un'espressione lambda.
Qual è la differenza tra un'interfaccia funzionale Java e le interfacce SAM in altri linguaggi, come C#?
In Java non esiste una parola chiave diretta per dichiarare interfacce SAM fino all'arrivo dell'annotazione @FunctionalInterface. A differenza di C#, dove delegate definisce chiaramente la firma, in Java è sufficiente avere un metodo astratto e un'annotazione facoltativa per il compilatore.
@FunctionalInterface — il compilatore non genera immediatamente un errore se l'interfaccia smette di essere funzionale.In un grande progetto, si è deciso di utilizzare le lambda ovunque, anche dove le entità rappresentavano dati, non direttamente correlati alla logica di business. Di conseguenza, la logica complessa era difficile da seguire, le lambda mascheravano le intenzioni del codice e il debugging diventava problematico.
Pro:
Contro:
In un altro progetto, è stata effettuata un'analisi approfondita su quali interfacce fossero adatte per la FP. Sono state utilizzate Predicate, Function e interfacce proprie per la gestione di collezioni ed eventi. Per le entità e la memorizzazione dei dati, la FP non è stata applicata.
Pro:
Contro: