Expressions lambda Java - Mémo

Nous pouvons depuis la version 8 de Java faire des choses intéressantes avec les expressions lambda, notamment avec toutes les fonctions pour avec les streams. Voici les 10 choses utiles à faire avec les expressions lambda.


Remplacer les classes internes

Les classes internes pouvaient être assez longue et difficilement lisible. Maintenant nous pouvons utiliser une expression lambda beaucoup plus concise.

// Avant Java 8 avec les classes internes
 new Thread(new Runnable() {
 @Override
   public void run() {
    System.out.println("Avant Java 8 avec les classes internes");
 }
 }).start();
 
// Après Java 8 avec les expressions lambda
new Thread(() -> System.out.println("Java 8 avec les expressions lambda")).start();

Ou encore avec les Handler de JavaFx :

Button btn = new Button("OK");
btn.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler < MouseEvent > () {
 @Override
 public void handle(MouseEvent e) {
  System.out.println("Assez long...");
 }
});

btn.addEventHandler(MouseEvent.MOUSE_CLICKED, e -> System.out.println("Beaucoup plus court"));

Attention, le mot-clé this dans une classe interne et dans une expression lambda n'a pas la même portée. Dans une classe interne, this correspond à l'objet créé. Alors que dans une expression lambda, le mot-clé this correspond à la classe où vous avez écrit l'expression lambda.

La nouvelle boucle forEach

La nouvelle boucle est aussi beaucoup plus courte et supporte en plus les tâches parallèles.

//Avant Java 8 
List < String > fruits = Arrays.asList("Pomme", "Poire", "Abricot", "Pêche", "Mangue");
for (String fruit: fruits)
 System.out.println(fruit);

//Après Java 8
Arrays.asList("Pomme", "Poire", "Abricot", "Pêche", "Mangue")
      .forEach(System.out::println);

Filtres et Prédicats

Les filtres et prédicats permettent de réduire une collection en filtrant les éléments. Voici comment ils fonctionnent :

fruits = Arrays.asList("Pomme", "Poire", "Abricot", "Pêche", "Mangue", "Citron");

System.out.println("Affiche tous les fruits commencant par 'P' : ");
fruits.stream()
      .filter(fruit -> fruit.toLowerCase().startsWith("p"))
      .forEach(System.out::println);

System.out.println("Affiche tous les fruits finissant par 'E' : ");
fruits.stream()
      .filter(fruit -> fruit.toLowerCase().endsWith("e"))
      .forEach(System.out::println);

System.out.println("Affiche tous les fruits avec 6 lettres : ");
fruits.stream()
      .filter(fruit -> fruit.length() == 6)
      .forEach(System.out::println);

System.out.println("Affiche aucun fruits : ");
fruits.stream()
      .filter(fruit -> false)
      .forEach(System.out::println);

System.out.println("Affiche les fruits avec 6 lettres et commençant par 'po' : ");
fruits.stream()
      .filter(fruit -> fruit.length() == 5)
      .filter(fruit -> fruit.toLowerCase().startsWith("po"))
      .forEach(System.out::println);

System.out.println("Affiche les fruits avec 5 lettres et commençant par 'po' : ");
Predicate < String > longueurDe5 = mot -> mot.length() == 5;
Predicate < String > lettrePo = mot -> mot.toLowerCase().startsWith("po");

fruits.stream()
      .filter(longueurDe5.and(lettrePo))
      .forEach(System.out::println);

Map

Map permet de faire des opérations sur un stream et d'en obtenir un nouveau. Imaginons que l'on veuille diviser tous les éléments d'une liste par deux.

List entiers = Arrays.asList(2, 4, 8, 16, 32, 64, 128, 256, 512, 1024);
System.out.println("Divise les entiers " + entiers + " par 2 : ");
entiers.stream()
       .map(x -> x / 2)
       .forEach(System.out::println);

 

Grâce au IntStream nous pouvons calculer la somme d'une liste d'Integer.

System.out.println("La somme de la liste " + entiers + " est égale à : " + 
  entiers.stream().mapToInt(Integer::intValue).sum());

Collecter une nouvelle liste

Pour convertir un stream en liste, il faut se servir de la fonction collect.

System.out.println("Collecte tous les fruits commencant par 'po' : ");
System.out.println(
    fruits.stream()
          .filter(fruit -> fruit.toLowerCase().startsWith("po"))
          .collect(Collectors.toList()));

Pour obtenir une chaîne de caractères, on peut se servir de Collectors.joining

System.out.println("Affiche les fruits commencant par 'P' séparés par des virgules : ");
System.out.println(
     fruits.stream()
           .filter(fruit -> fruit.toLowerCase().startsWith("p"))
           .collect(Collectors.joining(",")));

Enlever les doublons

Pour enlever les doublons il faut se servir de la fonction distinct. Cette fonction se sert de la fonction equals donc n'oubliez pas de l'implémenter.

entiers = Arrays.asList(12, 65, 16, 300, 250, 16, 65);
System.out.println("Affiche la liste " + entiers + " sans les doublons : ");
System.out.println(entiers.stream().distinct().collect(Collectors.toList()));

Statistiques

Pour obtenir des statistiques sur une collection de nombres on peut se servir de la classe IntSummaryStatistics, DoubleSummaryStatistics ou LongSummaryStatistics.

System.out.println("Affiche les statistiques de la liste " + entiers + " : ");
IntSummaryStatistics stats = entiers.stream().mapToInt(x -> x).summaryStatistics();
System.out.println("Maximum : " + stats.getMax());
System.out.println("Minimum : " + stats.getMin());
System.out.println("Moyenne : " + stats.getAverage());
System.out.println("Total : " + stats.getSum());
System.out.println("Nombre d'éléments : " + stats.getCount());

Limiter la taille d'un stream

Imaginons que nous voulons obtenir les trois premiers éléments du flux et les afficher dans la console.

System.out.println("Affiche les 3 premiers fruits : ");
fruits.stream()
      .limit(3)
      .forEach(System.out::println);

Trier un stream

Pour trier un stream on peut se servir de la fonction sorted.

System.out.println("Affiche la liste dans l'ordre alphabétique : ");
fruits.stream()
      .sorted()
      .forEach(System.out::println);

La fonction peut utiliser la méthode compareTo.

System.out.println("Affiche la liste par ordre alphabétique descendant : ");
fruits.stream()
      .sorted((fruit1, fruit2) -> fruit2.compareTo(fruit1))
      .forEach(System.out::println);

Sauter les éléments dans un stream

Pour sauter les éléments d'un stream on peut se servir de la fonction skip.

System.out.println("Saute les deux premiers éléments du flux : ");
fruits.stream()
      .skip(2)
      .forEach(System.out::println);

En vidéo

Le mémo en vidéo

Commentaires