Comprendre les bases des streams en Java par l’exemple

L’objectif de ce blog sera de vous introduire les bases des streams Java. On parlera des opérations intermédiaires telles que skip(), limit(), filter(), map(), sorted() et les opérations terminales allMatch(), anyMatch(), noneMatch(), findAny(), findFirst(), forEach(), min(), max(), count() et collect()

Comprendre les bases des streams en Java par l’exemple

Published by: Stephane, Last edited

Avec Java 8+ il est désormais possible d’utiliser les streams pour faciliter l'écriture des fonctionnalités de façon déclarative apportant plus de lisibilité dans le code. Dans ce blog on verra par des exemples l’utilisation des fonctionnalités de base des streams Java.

Nous ferons abstraction des interfaces fonctionnelles quoiqu’il soit absolument nécessaire de comprendre leur fonctionnement pour mieux appréhender les streams. On en parlera dans un prochain article.

Un exemple pour commencer: À supposer qu’on a une liste de nombres de 0 à 9 et qu’on désire compter les nombres pairs. On pourra écrire cette fonctionnalité de la sorte avec les streams.


List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
long count = nombres.stream().filter(x->x%2==0).count();
System.out.println(count);

A. Différence entre opérations intermédiaires et terminales

Les opérations intermédiaires sont les méthodes des streams qui retournent un stream. Et parce qu’elles retournent un stream on peut appeler d’autres méthodes à leurs suite. C’est le cas de filter() dans l’exemple précédent. Vous aurez donc compris que les opérations terminales terminent le stream, c’est à dire qu’on ne pourra plus appeler d’autres méthodes du stream à leurs suite, ce qui est le cas de count() dans l’exemple précédent qui retourne un long.

B. Les opérations intermédiaires

filter()

Cette méthode est utilisée pour filtrer les éléments d’un stream. Comme dans le premier exemple on peut filtrer les nombres pairs. Le critère de sélection dépendra de votre application.

Exemple: Nous avons une liste de nombre de 0 à 9 dont on voudrait retenir uniquement les nombres pairs


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    List filter = nombres
            .stream()
            .filter(x->x%2==0)
            .collect(Collectors.toList());
    System.out.println(filter);
    

Résultat: [0, 2, 4, 6, 8]

map()

Cette méthode est utilisée pour transformer les éléments de notre stream.

Exemple: nous avons une liste de nombres de 0 à 9 et nous voulons élever chaque nombre au carré.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    List map = nombres
                .stream()
                .map(x->x*x)
                .collect(Collectors.toList());
        System.out.println(map);
    

Résultat: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

skip()

Cette méthode est utilisée pour ignorer les x premiers éléments de notre stream.
Exemple: Avec notre liste de nombre de 0 à 9 on aimerait avoir uniquement les 6 derniers nombres.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    List skip = nombres
                .stream()
                .skip(4)
                .collect(Collectors.toList());
        System.out.println(skip);
    

Résultat: [4, 5, 6, 7, 8, 9]

limit()

Cette méthode est utilisée pour tenir compte uniquement des x premiers éléments de notre stream.
Exemple: Avec notre liste de nombres de 0 à 9, on aimerait avoir uniquement les 6 premiers nombres.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    List limit = nombres
                .stream()
                .limit(6)
                .collect(Collectors.toList());
        System.out.println(limit);
    

Résultat: [0, 1, 2, 3, 4, 5]

distinct()

Cette méthode permet d’ignorer les doublons dans une liste.
Exemple: Nous avons une liste d'éléments et on aimerai retirer tous les doublons.


    List nombres2 = Arrays.asList(0,1,2,3,0,2,4,5,6,1,7,8,9,9);
    List distinct = nombres2
            .stream()
            .distinct()
            .collect(Collectors.toList());
    System.out.println(distinct);
    

Résultat: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

sorted()

Cette méthode est utilisée pour ordonner les éléments du stream suivant leur ordre naturel (ordre alphabétique ou ordre numérique) ou en précisant le comparateur.
Exemple: On a une liste de nombres qu’on aimerait ordonner par ordre décroissant.


    List nombres3 = Arrays.asList(3,2,7,5,8,0,9,1,4,6);
    List sorted = nombres3
           .stream()
           .sorted(Comparator.reverseOrder())
           .collect(Collectors.toList());
    System.out.println(sorted);
    

Résultat: [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

C. Les operations terminales

A titre de rappel, les opérations terminales mettent fin au stream. En d’autre terme une fois l’une des méthodes ci-dessous invoquée, vous ne pourrez plus appeler une quelconque autre méthode du stream. Il en va de soit donc que vous ne pouvez pas avoir deux opérations terminales dans le même stream.

allMatch()

Cette méthode est utilisée pour vérifier si tous les éléments d’une liste vérifient une condition.
Exemple: nous avons une liste de nombre de 0-9 et nous aimerions savoir si tous ces nombres sont pairs.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    boolean allMatch = nombres
        .stream()
        .allMatch(x -> x%2==0);
    System.out.println(allMatch);
    

Résultat: false

anyMatch()

Cette méthode est utilisée pour savoir si au moins un élément d’une liste vérifie une condition.
Exemple: nous avons une liste de nombres compris entre 0 et 9 et nous aimerions savoir si il y’a au moins un nombre pair.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    boolean anyMatch = nombres
        .stream()
        .anyMatch(x -> x%2==0);
    System.out.println(anyMatch);
    

Résultat: true

noneMatch()

Cette méthode est l’opposée de anyMatch() car elle est utilisée pour vérifier qu’aucun élément du stream ne vérifie la condition.
Exemple: nous avons une liste de nombre compris entre 0 et 9 et nous voudrions savoir si tous les éléments sont des nombres pairs.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    boolean noneMatch = nombres
        .stream()
        .noneMatch(x -> x%2==0);
    System.out.println(noneMatch);
    

Résultat: false

findAny()

Cette méthode est utilisée pour retrouver un élément du stream. En général, elle retourne le premier élément sauf pour les streams parallèles qui peuvent retourner un autre élément.
Exemple: nous avons une liste de nombres compris entre 0 et 9 et nous aimerions retrouver un nombre pair.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    Optional findAny = nombres
           .stream()
           .findAny();
    System.out.println(findAny.get());
    

Résultat: 0

findFirst()

Cette méthode est utilisée pour trouver le premier élément du stream.
Exemple: nous avons une liste de nombres compris entre 0 et 9 et nous aimerions trouver le premier nombre pair.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    Optional findFirst = nombres
           .stream()
           .findFirst();
    System.out.println(findFirst.get());
    

Résultat: 0

forEach()

Cette méthode est utilisée pour parcourir tous les éléments d’une liste. Elle est particulièrement utile pour débugger le stream en imprimant son contenu.
Exemple: nous avons une liste de nombres compris entre 0 et 9 et on aimerait imprimer à la console tous ces éléments.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    nombres.stream()
           .forEach(x -> System.out.print(x+","));
    

Résultat: 0,1,2,3,4,5,6,7,8,9,

min()

Cette méthode est utilisée pour trouver le plus petit élément d’une liste. Elle peut accepter un comparateur pour pouvoir ordonner les éléments. Dans cet article, j’explique les bases des comparateurs.
Exemple: nous avons une liste de nombres et nous voudrions trouver le plus petit nombre.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    Optional min = nombres
           .stream()
           .min(Comparator.comparingInt(x->x));
    System.out.println(min.get());
    

Résultat: 0

max()

Cette méthode est utilisée pour trouver le plus grand élément d’une liste. Elle peut accepter un comparateur pour pouvoir ordonner les éléments.
Exemple: nous avons une liste de nombres et nous voudrions trouver le plus petit nombre.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    Optional max = nombres
           .stream()
           .max(Comparator.comparingInt(x->x));
    System.out.println(max.get());
    

Résultat: 9

count()

Cette méthode est utilisée pour compter le nombre d’éléments contenu dans le stream.
Exemple: nous avons une liste de nombres compris entre 0 et 9 et nous aimerions savoir le nombre total d’éléments contenu dans la liste.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    long count = nombres
        .stream()
        .count();
    System.out.println(count);
    

Résultat: 10

collect()

Cette méthode est utilisée pour récupérer le résultat de notre opération sur les streams sous forme d’une collection (liste, set, queues).
Exemple: après avoir filtré une liste de nombres pour ne garder que les nombres pairs, nous voulons récupérer le résultat sous forme de liste.


    List nombres = Arrays.asList(0,1,2,3,4,5,6,7,8,9);
    List pair = nombres
           .stream()
           .filter(x->x%2==0)
           .collect(Collectors.toList());
    System.out.println(pair);
    

Résultat: [0, 2, 4, 6, 8]

D. Mettons tout cela ensemble

Prises individuellement, ces méthodes ne sont pas très utiles par contre mises ensemble, vous pourriez résoudre des problèmes plus complexes de façon simple et claire.

Problème: Dans une salle de classe on aimerait trouver les 3 premiers élèves de sexe féminin en fonction de leur moyenne et les classer par ordre décroissant de moyenne.

Résultat: [Eleve{nom='Isabelle', moyenne=17, sexe=FEMALE}, Eleve{nom='Josiane', moyenne=16, sexe=FEMALE}, Eleve{nom='Claire', moyenne=14, sexe=FEMALE}]

Conclusion

Dans ce blog nous avons vu la différence entre les opérations intermédiaires et terminales de même que le fonctionnement de quelques unes de ses méthodes. J'espère que vous avez été édifié à ce sujet.

Find me on twitter or on

"Je puis tout par Christ qui me fortifie." Phil 4:13