:: Enseignements :: Master :: M1 :: 2015-2016 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) |
Liste, table de hachage, entrée/sortie, stream, lambdas
|
L'installation des nouvelles versions du JDK et de Eclipse n'a pas encore été faite par le CRI,
donc nous allons travailler avec des versions installées à la main.
Eclipse s'exécute en tapant dans un terminal :
eclipse-lambda
Une fois démarré, il faut le configurer pour qu'il utilise le bon JDK,
donc dans Window > Preferences > Java > Installed JREs, cliquer sur Add,
choisir "Standard VM" puis entrer le chemin /home/ens/forax/java8/jdk1.8.0_20/,
puis cliquer sur "Finish". Enfin, selectionner le JDK que vous venez de créer comme
JRE par défaut.
Eclipse va maintenant utiliser le JDK 8, il reste à lui dire d'utiliser le compilateur 1.8,
dans Window > Preferences > Java > Compiler, le Compiler compliance level doit être à 1.8
ouf, c'est fait !
Exercice 1 - Path, Stream et try-with-resources
On cherche à écrire un code correct permettant d'afficher les lignes d'un fichier.
-
Avant propos, rappeler pourquoi depuis la version 7 de Java, on représente un chemin en Java en utilisant la classe java.nio.file.Path
et pas la classe java.io.File comme précédemment.
-
Créer un Path en utilisant la factory method Paths.get() sur le fichier movies.txt.
-
En utilisant la méthode Files.lines
qui permet d'extraire toutes les lignes d'un fichier, afficher celles-ci à l'aide de la méthode forEach.
-
En fait, le code que vous écrit est faux, car vous avez ouvert un fichier, vu celui-ci comme un Stream mais vous avez oublié de fermer
le Stream pour fermer le fichier sous-jacent avec la méthode close.
Modifiez votre code.
-
Le code est encore faux car si vous avez une exception lors du forEach, la méthode close ne sera jamais appelée.
Modifiez votre code en utilisant la construction try/finally pour résoudre le problème.
-
En fait, il est plus pratique d'utiliser la construction try-with-resources, le try(...) car dans ce cas
l'appel à close est fait automatiquement à la fin du bloc try.
Modifiez une nouvelle fois votre code.
-
A la maison, faite une recherche pour savoir pourquoi le try(..) est mieux que le try/finally.
Notez que les deux premiers codes que vous avez écrits semblaient bons et marchaient alors qu'ils étaient farcis de bugs.
C'est le gros problème des tests, ce n'est pas parce qu'un test affiche ce qu'il faut que le code est correct.
Exercice 2 - Scoobi Dooooo
Le but de cet exercice est de manipuler un ensemble de films,
extrait du fichier
movies.txt pour trouver
quel acteur a joué dans le plus de film.
-
Dans un premier temps, écrivez un code qui lit le fichier ligne à ligne avec la méthode
Files.lines
et qui stocke dans une table de hachage la liste des acteurs correspondante
(dans une Map<String, List<String>> donc).
Pour séparer une chaine de caractères en plusieurs parties, il existe la méthode
String.split().
Il existe de plus une méthode
Stream.skip()
qui permet de ne pas prendre en compte des valeurs dans un stream.
-
On cherche maintenant à afficher le nombre total d'acteurs ayant jouer dans
au moins un film.
L'astuce consiste à ne pas se préoccuper des films mais uniquement des acteurs et donc dans un premier temps de créer un Stream d'acteur.
A quoi sert la méthode
Stream.flatMap() ?
Comment peut on l'utiliser dans notre cas ?
Pour tester, affichez les 50 premiers acteurs à partir du Stream de tous les acteurs.
Utilisez limit pour les 50 premiers et forEach pour l'affichage.
-
Au lieu d'afficher les 50 premiers, comptez le nombre d'acteurs et affichez le résulat.
-
En fait, le calcul précédent est faux car nous pouvons compter le même acteur plusieurs fois,
il faut éviter les doublons !
Dans un premier temps, nous allons éviter les doublons en stockant les acteurs dans une structure de donnée
qui a la propriété de ne pas enregistrer les doublons.
Quelle est l'interface Java qui correspond à cette structure de donnée ?
Quelle implantation de l'interface allons nous choisir ?
Ecrire le code et trouver combien d'acteurs uniques ont joué dans des films ?
-
En fait, il existe une méthode
Stream.distinct().
Comment peut-on l'utiliser pour trouver le nombre total d'acteurs.
Ecrire le code correspondant.
-
On souhaite maintenant calculer le nombre de films pour chaque acteur.
Nous allons tricher, on va repartir de notre Stream d'acteur (non unique) et compter le nombre
d'apparition de chaque acteur.
Nous allons pour cela utiliser un Collector particulier appelé
Collectors.groupingBy(Function).
Rappeler comment marche la méthode collect et les Collector.
Comment peut on utiliser le collecteur ci-dessus pour grouper les acteurs en fonction d'eux-même ?
Quelle sera le type de retour de l'appel à collect ?
Ecrire le code puis afficher le résultat pour le premier acteur (quoi que cela veuille dire) histoire de voir quelque chose !
-
Il existe une méthode
Function.identity().
Comment peut-on l'utiliser dans notre cas ?
-
On aimerait ne pas avoir une liste d'acteurs comme valeur de la Map résultante mais plutôt directement le nombre de fois où un acteur apparait dans la liste.
Il est possible en Java de compter le nombre de fois où l'on voit un acteur pendant la création de la Map (lors de la collection).
On utilise pour cela une surcharge de la méthode
Collectors.html.groupingBy(Function, Collector)
qui prend en second paramètre un nouveau collecteur qui agira sur les valeurs de la Map.
Quelle collecteur doit on utiliser comme second collecteur (downstream collector en anglais) ?
Utilisez celui-ci pour calculer le nombre de films pour chaque acteur,
dans une Map<String, Long>.
Vous pouvez afficher le premier acteur histoire de voir quelque chose et aussi vérifier que la taille de la Map correspond bien au nombre d'acteurs uniques trouvés précédemment.
Indication: les Collector par défaut sont déclarés dans la classe Collectors !
-
Il reste enfin à trouver l'acteur (le couple nom d'acteur/nombre de films) qui joue dans le plus de films.
Pour cela, il faut voir la Map comme un ensemble de couples clés/valeurs (en utilisant entrySet) puis
trouver le couple ayant le plus grand nombre de films grâce à la méthode
Collectors.maxBy().
Ecrire le code correspondant, trouver l'acteur ayant joué dans le plus de films et vérifier avec wikipedia que cela à un rapport avec le titre de l'exercice.
© Université de Marne-la-Vallée