Pubblicato il 24/02/2024 da alnao nella categoria Java & Spring Boot

Una delle evoluzioni principali dalla versione 8 di Java è stata l’introduzioni delle “Lambda Function” dette anche “Java Lambda Expression” che permettono di scrivere del codice senza dovergli dare un nome (metodo o classe), le possibili sintassi di questa tecnica prevedono 3 tipi sinonimi a seconda del numero di parametri e del numero di istruzioni nel blocco:

parameter -> expression
(parameter1, parameter2) -> expression
(parameter1, parameter2) -> { code block }

Il caso più semplice e più usato è l’uso delle lambda function per definire l’iterazione di una lista:

import java.util.ArrayList;
public class Main {
  public static void main(String[] args) {
    ArrayList<Integer> numbers = new ArrayList<Integer>();
    numbers.add(5);
    numbers.add(9);
    numbers.add(8);
    numbers.add(1);
    numbers.forEach( (n) -> { System.out.println(n); } );
  }
}

Ma allo stesso modo è possibile definire un oggetto “codice”:

import java.util.function.Consumer;
...
Consumer<Integer> method = (n) -> { System.out.println(n); };
numbers.forEach( method );

Si rimanda alla documentazione ufficiale, il quick start presentato dal sito ufficiale e alla pagina w3c per maggiori dettagli.


L’uso di questa tecnica è usato in moltissimi casi specifici, si elencano alcuni esempi dove il codice classi può essere sostituito con questa tecnica:

  • definizione del comportamento di un bottone:
    bottone.setOnAction(
      event -> System.out.println("Click done")
    );
  • filtri con ciclo for:
    public List<Persona> getMaschi(iscritti){
      List<Persona> persone = new ArrayList<Persona>();
      for (Persona p:iscritti)
        if (isMaschio(p))
          persone.add(p);
      return persone;
    }
  • filtri con metodo:
    Predicate<Persona> allMaschi = p -> p.getSesso().equals("M");
    public List<Persona> getIscrittiFiltratiPer(Predicate<Persona> pred){
      List<Persona> persone = new ArrayList<Persona>();
      for (Persona p:iscritti)
        if (pred.test(p))
          persone.add(p);
      return persone;
    }
    ms.getIscrittiFiltratiPer(allMaschi);
  • logiche annidate sulle liste con filter e map:
    lista.stream()
    .filter( p -> p.getGender() == Person.Sex.MALE) //filtrare elementi di una lista
    .map(p -> p.getEmailAddress()) //funzione map per modificare un elemento
    .forEach(email -> System.out.println(email));
  • definizione di interfacce funzionali:
    package java.awt.event;
    import java.util.EventListener;
    public interface ActionListener extends EventListener {
      public void actionPerformed(ActionEvent e);
    }
  • runnable block:
    public class RunnableTest {
      public static void main(String[] args) {
        System.out.println("=== RunnableTest ===");
        Runnable r1 = new Runnable(){// Anonymous Runnable
        
        @Override
        public void run(){
          System.out.println("Hello world old style!");
        }
      };
      // Lambda Runnable
      Runnable r2 = () -> System.out.println("Hello world with Lambda!");
        r1.run();
        r2.run(); 
      }
    }

La tecnica delle Lambda Function è stata introdotta per semplificare la vita dei programmatori, assieme alla tecnica delle classi innestate, questa tecnica è molto utile e usata tuttavia spesso rende il codice molto meno leggibile e l’utilizzo deve sempre essere pensato, si rimanda alla pagina ufficiale che consiglia quando usare e quando non usare queste tecniche.

Una nota obbligatoria è il nome di queste funzioni: “Lambda Function” e “Lambda Expression” sono nomi usati anche da altre tecnologie, come le lambda function di AWS, per questo motivo è sempre consigliato usare il nome con il linguaggio di programmazione “Java Lambda Function” per evitare fraintendimenti, poi ovviamente è possibile usare “Java Lambda Function” per definire delle “AWS Lambda Function” ma questa è una sega mentale di noi programmatori che lavorano con Java in Cloud.

MENU