Stream, map, filter et reduce en java 8

Après avoir échappé pendant quelques années à la programmation fonctionnelle qui revient sur le devant de la seine, Java à finalement adopté les quelques principes de la programmation fonctionnelle au printemps 2014. Java 8 comprend un support pour les expressions lambda et offre une puissante API Streams qui vous permet de travailler avec des séquences d'éléments tels que les listes et les tableaux avec une nouvelle manière de faire.

Dans ce tuto, nous allons essayer de montrer comment créer des flux (steams), afin de les transformer par la suite en utilisant map , filter et reduce qui sont des méthodes proposées dans la version java 8.

Stream

Un stream n'est qu'une séquence d'éléments. Bien qu'il existe de nombreuses approches pour la création d’un stream, pour l'instant, nous nous concentrerons uniquement sur la génération de stream des listes et des tableaux.

Dans Java 8, chaque classe qui implémente cette interface possède une méthode qui vous permet de convertir ses instances en objets. Par conséquent, il est trivialement facile de convertir une liste en stream. Voici un exemple qui convertit l'un des objets en un stream

// Création de la liste
List list = new ArrayList <>();
list.add(1);
list.add(2);
list.add(3);
// Conversion de la liste en stream
Stream <> stream = list.stream();

Nous pouvons aussi appliquer un stream sur les tableaux

// Création du tableau
Integer[ ] array = {1, 5, 8};
// Conversion du tableau en stream
Stream <> stream = Arrays.stream(array);

La méthode map

Une fois que vous obtenez un objet stream, vous pouvez utiliser une variété de méthodes pour le transformer en un autre stream. La première méthode que nous allons examiner est la méthode map. cette expression lambda est utilisée pour changer chaque élément individuel dans le stream. Sa valeur de retour est un nouvel objet stream contenant les éléments modifiés.

Pour vous donner un exemple réaliste, permettez-moi de vous montrer comment vous pouvez utiliser map pour convertir tous les éléments d'un ensemble de chaînes en majuscules.

Ensuite, vous pouvez appelez la méthode map, en passant une expression lambda, qui peut convertir une chaîne en majuscule, en tant que seul argument:

String[ ] array = new String[ ]{"toto", "titi", "tata", "tete"};
Stream stream = Arrays.stream(array);
Stream newStream = stream.map(s -> s.toUpperCase());

Puis à la fin vous obtenez un nouveau tableau un ensemble de chaînes, toutes en majuscules

String[ ] newArray = newStream.toArray(String[ ]::new);

La méthode filter

Dans la section précédente, vous avez vu que la map traite chaque élément dans un objet stream. Vous pourriez ne pas toujours vouloir cela. Parfois, vous voudrez peut-être travailler avec seulement un sous-ensemble des éléments. Pour cela, vous pouvez utiliser la méthode filter.

Tout comme la map, filter attend une expression lambda comme argument. Cependant, l'expression lambda qui lui est transmise doit toujours renvoyer un boolean qui détermine si l'élément traité doit ou non appartenir à l' objet Stream résultant .

Par exemple, si vous disposez d'un ensemble de chaînes et que vous souhaitez créer un sous-ensemble qui contient uniquement les chaînes dont la longueur est supérieure à quatre caractères, vous devez écrire le code suivant:

Arrays.stream(array) .filter(s -> s.length() > 4) .toArray(String[]::new);

Le code ci-dessus est beaucoup plus concis que le code que nous avons écrit dans l'exemple précédent parce que j'ai enchaîné toutes les méthodes Stream. La plupart des développeurs préfèrent écrire le code fonctionnel de cette manière, car, habituellement, il n'est pas nécessaire de stocker des références sur des objets stream intermédiaires.

La méthode reduce

Une opération reduce est celle qui vous permet de calculer un résultat en utilisant tous les éléments présents dans un strem. Les opérations de réduction sont également appelées opérations de terminal car elles sont toujours présentes à la fin d'une chaîne de la méthode stream. Nous utilisons déjà une méthode de réduction dans nos exemples précédents: la toArray. C'est une opération de terminal car elle convertit un stream objet en un tableau.

Java 8 comprend plusieurs méthodes de réduction, telles que sum, averageet count qui permettent d'effectuer des opérations arithmétiques sur des stream objets et d'obtenir des nombres en tant que résultats. Par exemple, si vous souhaitez trouver la somme d'un ensemble d'entiers, vous pouvez utiliser le code suivant:

int array[ ] = { 1, 5, 8 };
int sum = Arrays.stream(array).sum();

Si vous souhaitez effectuer des opérations de réduction plus complexes, vous devez utiliser la méthode reduce. Contrairement aux méthodes map et filter, le reduce s'attend à deux arguments: un élément d'identité et une expression lambda. Vous pouvez considérer l'élément d'identité comme un élément qui ne modifie pas le résultat de l'opération de réduction. Par exemple, si vous essayez de trouver le produit de tous les éléments dans un stream de nombres, l'élément d'identité serait le numéro 1.

L'expression lambda que vous passez à la méthode reduce doit être capable de gérer deux entrées: un résultat partiel de l'opération de réduction et l'élément actuel du stream. Si vous vous demandez quel résultat partiel, c'est le résultat obtenu après le traitement de tous les éléments du stream précédant l'élément actuel.

Voici un exemple d'extrait de code qui utilise la méthode reduce pour concaténer tous les éléments dans un ensemble d'objets string:

String[ ] array = { "le", "java", "c'est", "fun" };
String result = Arrays.stream(array)
.reduce("", (a,b) -> a + b);

Pour en savoir plus sur l'API Streams et les autres méthodes qu'elle offre, vous pouvez consulter sa documentation .