:: Enseignements :: Master :: M1 :: 2014-2015 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
Lambda, method reference et stream
|
Exercice 1 - Le compte est bon
Le but de cet exercice est de découvrir comment utiliser
des lambdas et des streams.
-
On cherche à compter le nombre d'occurence d'un mot dans une liste.
List<String> list = Arrays.asList("hello", "world", "hello", "lambda");
System.out.println(count(list, "hello"));
Ecrire le code de la méthode count sachant que le compteur
est un entier long.
-
On cherche à écrire une méthode count2 sémantiquement équivalente
(qui fait la même chose) que count mais en utilisant l'API
des Stream.
Comment obtenir un Stream à partir d'un objet de type List ?
L'idée, ici, est de filtrer le stream pour ne garder que les mots égaux
au mot passé en paramètre puis de compter ceux-ci.
Quelle est le nom des méthodes permettant respectivement de filtrer un stream
et de compter le nombre d'élement ?
La méthode qui permet de filtrer prend un objet de type Predicate<T>
en paramètre. Dans notre cas, quelle est le type correspondant à T ?
Indiquer le code permettant de créer une lambda filtrant sur le mot passé en
paramètre que l'on peut déclarer en tant que Predicate
Ecrire le code de la méthode count2.
-
Il est possible d'utiliser la syntaxe des méthodes références au lieu de celle
des lambdas pour implanter le filtre.
Modifier le code pour utiliser la syntaxe des méthodes références.
Exercice 2 - En majuscule
Le but de cet exercice est de découvrir comment utiliser
en plus des lambdas et des streams, des méthodes reférences.
-
On cherche écrire une méthode prenant en paramètre une liste de chaîne de caractères
et renvoyant une nouvelle liste contenant les chaînes de caractère en majuscule.
List<String> list = Arrays.asList("hello", "world", "hello", "lambda");
System.out.println(upperCase(list));
Ecrire la méthode upperCase dans un premier temps sans utiliser
l'API des Stream.
-
On cherche maintenant à écrire une méthode upperCase2 faisant
la même chose.
Comment peut-on utiliser la méthode Stream.map ici ?
Pour stocker le résultat dans une nouvelle liste, l'idée est de créer
la liste pour d'ajouter chaque mot dans la liste.
public static List<String> upperCase2(List<String> words) {
ArrayList<String> uppercases = new ArrayList<>();
...
pour demander l'ajout, on utilisera sur le stream la méthode forEach.
Ecrire le code de la méthode upperCase2 en utilisant des lambdas.
-
En fait, au lieu d'utiliser des lambdas, il est possible dans cette exemple
d'utiliser la syntaxe des réferences de méthodes avec l'opérateur ::
(coloncolon).
Ecrire une méthode upperCase3 qui utilise la syntaxe des
référence de méthodes.
-
En fait, au lieu d'utiliser forEach, il est plus pratique d'utiliser
la méthode collect avec comme Collector
celui renvoyé par la méthode Collectors.toList().
Ecrire une méthode upperCase4 en utilisant le collector
Collectors.toList().
Exercice 3 - Comptons sur une réduction
Le but de cet exercice est de découvrir comment utiliser
effectuer une reduction sur un stream.
Lors du premier exercice, nous avons utilisé la méthode count
qui retourne un entier long, on souhaite maintenant écrire une nouvelle
méthode count3 qui renvoie un entier sur 32 bits.
Pour cela, une fois les mots filtrés, nous allons transformer
(avec map) chaque mot en 1 (le nombre) puis nous allons
avec la méthode reduce faire l'aggregation des valeurs.
-
Expliquer pourquoi, nous n'allons pas utiliser la méthode map
mais la méthode mapToInt ?
-
Ecrire le code de la méthode méthode count3.
Si vous vous sentez perdu dans cet exercice, vous pouvez aller regarder
comment la méthode Stream.count() que nous avons vu au premier exercice
est implantée (un Ctrl+click sur une méthode dans Eclipse charge son code !).
Exercice 4 - Evaluation de vitesse
On cherche à savoir parmis les 3 façons d'écrire
count
quelle est la plus rapide.
Nous allong pour cela utiliser une liste définie par le code suivant
List<String> list2 =
new Random(0)
.ints(1_000_000, 0, 100)
.mapToObj(Integer::toString)
.collect(Collectors.toList());
-
Expliquer ce que contient la variable locale list2.
-
On cherche à écrire une méthode printAndTime permettant
de calculer le temps d'exécution de l'appel à la méthode count
sur la list2.
Pour calculer le temps d'exécution, on demande le temps avant puis
le temps après et si l'on soustrait les deux temps, on trouve le temps
d'exécution.
long start = System.nanoTime();
... // faire le calcul
long end = System.nanoTime();
System.out.println("result " + result);
System.out.println(" elapsed time " + (end - start));
Tester ce code en appelant la méthode count().
-
On cherche maintenant A NE PAS dupliquer le code ci-dessus dans le
cas où l'on appel count2 ou count3 mais à utiliser une méthode
printAndTime et de passer en paramètre la méthode count
qui doit être appelée.
Quelle doit être la signature de la méthode de l'interface fonctionnel tel que l'on puisse
appeler la méthode printAndTime comme ceci:
printAndTime(() -> count(list2, "33"));
printAndTime(() -> count2(list2, "33"));
printAndTime(() -> count3(list2, "33"));
Déclarer l'interface et ecrivez le nouveau code de printAndTime.
-
En fait, il existe déjà une interface
LongSupplier,
modifier le code de printAndTime pour utiliser cette interface.
-
Expliquer les résultats obtenus.
Que se passe t'il si on permute les appels à printAndTime ?
© Université de Marne-la-Vallée