Conception par Objet et Programmation Java

Programming, Math · course

Voir tous les documents en programmation

<!-- Slide number: 1 --> # Conception par Objet et Programmation Java 1

![](GoogleShape215p1.jpg)

Chapitre 10 : Les Stream Equipe Java 2019-2020

![](GoogleShape220p1.jpg)

Notes:

<!-- Slide number: 2 --> # Plan ‹#›

Introduction Classe et objet Encapsulation Héritage Polymorphisme Exceptions Interfaces Collections Lambda Expression Stream

Notes:

<!-- Slide number: 3 --> # Objectifs ‹#› Introduire le concept de stream

La programmation fonctionnelle

Manipulation des stream

Utilisation des interfaces fonctionnelles

Utilisation des Lambda expression

Notes:

<!-- Slide number: 4 --> # Programmation fonctionnelles ‹#› Le principe général de la programmation fonctionnelle est de concevoir des programmes comme des fonctions mathématiques que l'on compose entre elles. A la différence des programmes impératifs organisés en instructions produisent des effets de bords, les programmes fonctionnels sont bâtis sur des expressions dont la valeur est le résultat du programme.

Notes:

<!-- Slide number: 5 --> # Programmation fonctionnelles ‹#› Un programme fonctionnel consiste en une expression E (représentant l'algorithme et les entrées). Cette expression E est sujette à des règles de réécriture : la réduction consiste en un remplacement d'une partie de programme fonctionnel par une autre partie de programme selon une règle de réécriture bien définie. Ce processus de réduction sera répété jusqu'a l'obtention d'une expression irréductible (aucune partie ne peut être réécrite). L'expression E* ainsi obtenue est appelée forme normale (fn) de E et constitue la sortie du programme.

Notes:

<!-- Slide number: 6 --> # Stream: Définition ‹#›

Publicité

Un "Stream<T>" décrit une séquence d’éléments (de type T) supportant des opérations agrégées en séquence ou en parallèle.

L’API Stream fourni des classes pour supporter des opérations de style fonctionnel sur des flux de valeurs

Notes:

<!-- Slide number: 7 --> # Stream: Définition ‹#› Il est important de ne pas voir les "streams" comme une alternative aux collections mais plutôt comme un moyen de traitement associé :

Un "stream" n’est pas un moyen de stockage, il ne fait que transmettre des données provenant d’une source (collection, tableau, générateur de données, canal d’E/S, …) au travers d’une file d’opérations.

Un "stream" est fonctionnel par nature, une opération sur un "stream" produit un résultat mais ne modifie jamais sa source. Un filtrage, par exemple, crée un nouveau "stream" avec les éléments filtrés, il ne supprime rien de la source.

Notes:

<!-- Slide number: 8 --> # Stream: Définition ‹#› Un "stream" a un mode d’exécution paresseux. Les opérations d’un "stream" sont de deux types : intermédiaires (elles renvoient un "stream" comme le filtrage par exemple) ou terminales (comme la somme vue plus haut). Les opérations intermédiaires sont toujours implémentées de manière paresseuse, afin de profiter au maximum d’une éventuelle optimisation.

Un "stream" est un consommateur, ses éléments ne peuvent être visités qu’une seule fois pendant sa durée de vie, un nouveau "stream" doit donc être créé pour parcourir à nouveau la source.

Notes:

<!-- Slide number: 9 --> # Obtention d’un stream ‹#› Il existe plusieurs façons pour créer un "stream". La plus simple consiste à appeler la méthode "stream()" ou "parallelStream()" sur une collection, de plus un certain nombre de méthodes ont été ajoutées aux classes déjà existantes.

Un "stream" s’obtient de la manière suivante :

Depuis une Collection via la méthode "stream()" ou "parallelStream()" Depuis un tableau via "Arrays.stream(Object[])". Depuis des méthodes statiques de l’interface "Stream<T> comme "Stream.of(Object[])", "IntStream.range(int,int)" ou "Stream.iterate(Object, UnaryOperator) ". Lors de la lecture d’un fichier via "BufferedReader.lines()".

Notes:

<!-- Slide number: 10 --> # Opérations sur les stream ‹#›

L’intérêt principal d’un "stream" réside dans la possibilité d’effectuer plusieurs opérations plus ou moins complexes en les enchaînant en une seule instruction. Cet enchaînement, appelé pipeline, est composé de plusieurs opérations intermédiaires et d’une seule opération terminale.

Opérations intermédiaires :

Chaque opération intermédiaire retourne un nouveau "stream" (permettant ainsi l’enchaînement des opérations).

Notes:

Publicité

<!-- Slide number: 11 --> # Opérations sur les stream ‹#› Opérations intermédiaires principales :

De même type Stream<T> filter(Predicate<T>) Stream<T> sorted() Stream<T> sorted(Comparator<T> comparator) Stream<T> distinct() Stream<T> limit(long maxSize) Stream<T> peek(Consumer<T> action) : Stream<T> skip(long n)

De type différent <R> Stream<R> map(Function<T, R> mapper) R> Stream<R> flatMap(Function<T, Stream<R>> mapper)

Notes:

<!-- Slide number: 12 --> # Opérations sur les stream ‹#› Opérations terminales:

L’opération terminale d’un stream est une opération finale, celle qui déclenche l’exécution du pipeline d’opérations (et donc consomme le flux d’entrée), produit (éventuellement) un résultat puis ferme le "stream".

Opérations terminales principales :

Booléennes

Les opérations booléennes "allMatch", "anyMatch" et "noneMatch", qui prennent toutes les trois un "Predicate<T>" en paramètre, sont vraies lorsque, respectivement, tous les éléments, au moins un ou aucun satisfont le prédicat donné.

Notes:

<!-- Slide number: 13 --> # Opérations sur les stream ‹#› Numériques

- long count() : retourne le nombre d’éléments du "stream". - type sum() : retourne la somme des éléments du "stream" (type étant int, double ou long),

Simple

- Optional<T> findAny() : retourne un élément (n’importe lequel) du "stream". - Optional<T> findFirst() : retourne le premier élément du "stream". - Optional<T> max (Comparator<T>comparator) et Optional<T> min (Comparator<T>comparator) retournent respectivement le maximum et le minimum des éléments du "stream" en accord avec le comparateur donné.

Notes:

<!-- Slide number: 14 --> # Opérations sur les stream ‹#› Complexes

- Collect: "Collect" est une opération terminale extrêmement utile pour transformer les éléments d’un "stream" à un autre type de résultat, par exemple une "List", "Set" ou "Map".

- Reduce L'opération de réduction combine tous les éléments du "stream" en un seul résultat

Notes:

Publicité

<!-- Slide number: 15 --> # Ordre des opérations ‹#› Une caractéristique importante des opérations intermédiaires est la paresse ("laziness"). Regardez cet exemple où une opération terminale est manquante:

![](GoogleShape323p15.jpg) On exécutant ce bout de code, rien ne sera affiché à la console. C’est parce que les opérations intermédiaires ne seront exécutés que lorsque une opération terminale est présente.

Notes:

<!-- Slide number: 16 --> # Ordre des opérations: Exemple 1/4 ‹#› Étendons l'exemple ci-dessus par l'opération terminale "forEach":

![](GoogleShape333p16.jpg) On exécutant ce bout de code, rien ne sera affiché à la console. C’est parce que les opérations intermédiaires ne seront exécutés que lorsque une opération terminale est présente.

Notes:

<!-- Slide number: 17 --> # Ordre des opérations: Exemple 2/4 ‹#› Pourquoi l'ordre est important

L'exemple suivant est constitué de deux opérations intermédiaires "map" et "filtre" et une opération terminale "forEach". Essayons de nouveau de voir de près la manière dont ces opérations sont exécutées:

![](GoogleShape340p17.jpg)

Notes:

<!-- Slide number: 18 --> # Ordre des opérations: Exemple 3/4 ‹#› Comme vous l'aurez deviné les opérations "map" et "filtre" sont appelées cinq fois dans la collection alors que la méthode "forEach" est appelée une seule fois. Nous pouvons réduire le nombre réel d'exécutions si nous changeons l'ordre des opérations, en déplaçant "filtre" au début de la chaîne:

![](GoogleShape348p18.jpg)

Notes:

<!-- Slide number: 19 --> # Ordre des opérations: Exemple 4/4 ‹#› Maintenant, la méthode "map" est appelée une seule d’où les opérations du pipe-line beaucoup plus rapide pour un nombre d'éléments d’élément plus grand. Gardez cela à l'esprit lors de la composition d’une chaîne des méthodes complexes.

Notes: