API Stream
Programmation fonctionnelle
Comme vous le savez, Java est un langage de programmation multi-paradigme. Vous avez pu traiter la programmation orientée objet, la programmation procédurale et nous allons désormais découvrir la programmation fonctionnelle.
Cette approche a été renforcée dans Java 8 avec l'introduction d'une nouvelle amélioration syntaxique puissante sous la forme d'expressions lambda.
Lambda
Une expression lambda est une fonction anonyme que nous pouvons traiter de la même manière que n'importe quel autre objet. Cela signifie qu'elle peut être utilisée de manière flexible, telle que la passer en tant qu'argument de méthode ou encore en valeur de retour.
L'interface fonctionnelle est un exemple qui permet de bien comprendre le principe de lambda
.
Voici un exemple de BiFunction :
Voici quelques points à savoir sur les lambda :
- Il n'est pas obligatoire de mettre les parenthèses s'il n'y a qu'un seul paramètre.
- Vous pouvez omettre le bloc de code après la flèche s'il n'y a qu'une seule instruction
return
(cf. ligne 12).
Le plus souvent, les lambda iront de pair avec un autre concept Java apparu dans la même version : les streams. Les streams sont une extension naturelle des lambdas, offrant une approche de code plus lisible et maintenable pour manipuler des collections de données.
Streams
Qu'est-ce qu'un Stream ?
Un Stream est un objet qui encapsule un flux de données sur lequel on peut effectuer des opérations. Son utilisation est très répandue, voire privilégiée pour beaucoup de cas d'utilisation.
Il existe deux types d'opérations que l'on peut effectuer sur des streams :
- les opérations terminales : on récupère le résultat à l'issue de l'opération
- les opérations intermédiaires : opérations intermédiaires qui modifient le flux
Concrètement, là où l'on aurait utilisé une boucle for
sur une collection pour modifier ses éléments, nous allons désormais préférer utiliser des streams et appliquer des fonctions de modification sur les différents éléments de la collection.
Toutes les collections qui étendent l'API Collection
proposent une méthode stream()
qui permet de récupérer un objet Stream sur lequel appliquer des opérations.
Opérations sur les Streams
Opérations terminales :
- reduce(identity, accumulator, combiner) : combine les éléments d'une collection en utilisant une valeur initiale, une opération d'accumulation et une opération de combinaison
- forEach(element) : itère sur la collection avec
element
comme valeur courante - collect : permet de transformer le stream en une valeur (List, Double, ...)
- min/max(comparator) : renvoie un Optional
qui contient la valeur min/max de la collection trouvée en appliquant comparator
à tous les éléments deux à deux - anyMatch(predicate) : évalue le fait qu'au moins un élément de la collection valide le
predicate
- findFirst : renvoie un Optional
du premier élément du Stream - findAny : renvoie un Optional
d'un élément du Stream
Opérations intermédiaires :
- filter(predicate) : renvoie une sous collection des éléments qui valident le
predicate
- map(mapping) : renvoie une collection où l'on a appliqué
mapping
à tous les éléments - distinct : renvoie un Stream qui ne contient pas de doublons
- sorted : trie les éléments du Stream
- limit(n) : limite le Stream à
n
éléments
Exemple
Étant donné la collection suivante :
On veut écrire un stream qui renvoie la somme des tailles des chaînes de caractères présentes dans la liste. Ce stream enlève les valeurs vides et calcule la somme des tailles des chaînes de caractères présentes dans la liste.Requêtage de notre application
Maintenant que vous avez appréhendé les Streams, il est l'heure d'ajouter des fonctionnalités de requêtage à notre application.
Nous vous proposons un jeu de données à ajouter avant de commencer cette partie.
À vous de jouer
Il faudra, pour chaque fonctionnalité, coder une méthode dans le service associé à la fonctionnalité. Quasiment toutes ces méthodes prendront un paramatre List<Travel>
.
Voici les différentes fonctionnalités :
- Notre agence doit pouvoir exposer la liste de tous les voyages disponibles actuellement (donc pour lesquels il reste encore des places)
- Dans un second temps, nous voulons pouvoir paramétrer cette liste de voyages disponibles par une localisation. Exemple : tous les voyages disponibles à destination de Tokyo
- Nos utilisateurs aimeraient faire une recherche détaillée sur les voyages que propose l'agence dans une certaine fourchette de prix.
- Nos utilisateurs aimeraient avoir le voyage le plus proche de la date actuelle.
Optionnel
Si vous avez bien progressé et qu'il vous reste du temps, continuez à implémenter ces fonctionnalités :
- L'agence doit pouvoir lister la liste des n premiers voyages triés par ordre croissant de prix.
- Elle devra pouvoir également lister tous les voyages disponibles avec une promotion en cours.
-
Nous voulons que l'agence puisse lister tous les voyages auxquels le
User
Jean-Michel est inscrit (Il faudrait pouvoir filtrer sur les user qui match la condition). -
Il y a un nouveau CEO dans l'entreprise. Il veut pouvoir évaluer la rentabilité de notre agence et il souhaiterait obtenir la moyenne du prix des voyages proposés par l'agence.
Essayez votre code dans le Main
À vous de jouer
Vous pouvez maintenant tester votre service dans le main.
...
// Ma liste de voyages
List<Travel> travels = new LinkedList();
travels.add(new Travel(0, "To New York", Airport.PARIS_CHARLES_DE_GAULLE, Airport.NEW_YORK_JFK,
Instant.now().plus(Duration.ofDays(2)),
Instant.now().plus(Duration.ofDays(15)), "NewYork", 6, 3500));
travels.add(new Travel(0, "Paris is next", Airport.TOKYO_HANEDA, Airport.PARIS_ORLY,
Instant.now().minus(Duration.ofDays(2)),
Instant.now().plus(Duration.ofDays(5)),"Paris", 10, 2900));
// instancier mon service
TravelService travelService = new TravelService();
// récupérer que les voyages disponible
List<Travel> availableTravels = findAvailableTravels(travels);
...
Récapitulatif
Excellent, nous avons clôturé la partie sur les streams et vous avez pu créer vos programmes de recherche.
N'oubliez pas de Commit
votre travail !
Conclusion
On est arrivé à la fin de cette première partie de la formation. À demain pour de nouvelles aventures !