:: Enseignements :: ESIPE :: E4INFO :: 2011-2012 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | foreach, filter, map, reduce |
Le but de ce TD est d'implanter les méthodes dite fonctionnelles
que l'on trouve habituellement sur les collections de language comme Python ou Ruby.
L'interface
FunIterable est un
Iterable
qui ajoute les méthodes
forEach,
toList et
filter.
Les méthodes de
FunIterable sont définies comme ceci:
-
La méthode forEach() appel la méthode apply
d'un Block pour chaque élement.
-
La méthode toList() copie l'ensemble des élements
de l'Iterable dans la liste passée en paramétre.
-
La méthode filter() renvoie un FunIterable
qui filtre les élements du FunIterable courant.
Avec les interfaces
Block et
Filter définie comme ceci:
Exercice 1 - FunUtils
Le but de cette exercice est de founir une implantation de l'interface
FunIterable pour cela, la classe FunUtils contiendra
un ensemble de méthode statique aidant à l'implantation de l'interface
FunIterable.
-
On souhaite écrire une méthode filterIterator qui prend en paramètre un
Iterable et un filtre Filter et renvoie un
Iterator qui parcours l'ensemble des élements de l'iterable
pour lequel la méthode accept du filter renvoie vrai.
Expliquer pourquoi la méthode remove ne peut pas être implanté.
Implanter la méthode filterIterator.
-
Vérifié que le code suivant compile:
Iterable<String> iterable = Arrays.asList("foo", "bar");
Iterator<String> iterator = FunUtils.filterIterator(iterable,
new Filter<Object>() {
public boolean accept(Object o) {
return o.toString().length() % 2 == 0;
}
});
Si le code ne compile pas, modifier la signature de la méthode filterIterator
pour qu'il compile.
-
Modifier le code prédent pour que l'appel à filterIterator
renvoie un Iterator<CharSequence>.
Pourquoi le compilateur n'est pas capable de trouver tout seul E ?
-
De la même façon, les signatures des méthodes forEach, toList et
filter de l'interface FunIterable ne sont pas les bonnes,
modifier les en conséquence.
-
Ecrire une méthode and qui prend deux Filter en paramétre
et qui renvoie un nouveau Filter dont la méthode accept
renverra vrai si les des deux filtres sont vrais.
On cherche de plus à ce que l'implantation soit lazy comme le 'et' booleéen en C (ou en Java).
-
Ecrire une méthode trueFilter qui renvoie un filtre dont la méthode accepte
renvoie toujours vrai.
Noter que ce filtre ne dépend pas du type d'élement passé en paramètre,
donc il est possible d'utiliser un même objet filtre que cela soit un Filter<String>
ou un Filter<Object>.
On stockera donc cette unique filtre comme une constante;
-
Ecrire une méthode asFunIterable qui renvoie un FunIterable à partir
d'un Iterable et d'un Filter.
Noter que comme la méthode filter de l'interface FunIterable
renvoie aussi un FunIterable filtré, la classe implantant
FunIterable ne doit pas être une classe anonyme.
-
Modifier le code de filter de la classe implantatant
FunIterable en remarquant qu'il est possible de détecter
si le FunIterable a été construit avec le filtre trueFilter,
et donc qu'il n'est alors pas nécessaire d'utiliser and.
-
Le test Junit est
FunUtilsTest.java.
Si certaine méthodes ne compile pas c'est que vous vous êtes tromper
dans la signature de la méthode.
Exercice 2 - FunUtil2
On cherche maintenant à écrire un
Iterateur qui associe
à un élement un autre élement en utilisant une fonction
définie par l'interface
Mapper.
-
Dans une classe FunUtils2, écrire une méthode
mapperIterator qui prend en paramètre un Iterable
et un Mapper et qui renvoie un Iterateur dont
chaque élement renvoyé est le résultat de l'appel à la méthode map
sur les élement de l'iterable passé en paramétre.
Que dire de la méthode remove ?
-
Ecrire une méthode compose qui prend deux Mapper en paramètre
qui renvoie un mapper qui agit comme une composition de fonction.
-
Ecrire une méthode identityMapper qui renvoie un mapper
qui renvoie le même objet que celui qu'on lui passe en paramètre.
Noter que ici aussi, il n'est pas nécessaire d'allouer l'objet
correspondant au mapper identité à chaque fois que l'on appel
la méthode identityMapper.
-
Ajouter à l'interface FunIterable la méthode map
qui prend en Mapper en paramètre et qui renvoie un nouveau FunIterable
dont l'iterateur renvoie les images des élements du FunIterable courant
par la fonction de mapping.
Noter que la signature est commentaire dans l'interface n'est pas la bonne,
quelle doit être la bonne signature.
-
Ecrire une méthode asFunIterable dans la classe FunUtils2
qui prend un iterable et un mapper en paramètre et renvoie un FunIterable.
La méthode map devra être optimisé pour éviter de créer des
FunIterable si cela n'est pas nécessaire.
Noter qu'il vous faudra aussi changer l'implantation dans FunUtils
car on vient de changer l'interface
Exercice 3 - FunUtil3
On cherche enfin à avoir une implantation de FunIterable
qui permette de filtrer et mapper en une seule opération i.e sans
créer des FunIterable de FunIterable.
-
Ecrire, dans la classe FunUtils3 une méthode mapFilterIterator
qui prend en paramètre un iterable, un filter puis un mapper et renvoie
un iterateur des élements filtrés puis mappés.
Que peut-on dire sur la méthode remove de l'iterateur.
-
Ecrire la méthode asFunIterable qui prend en paramètre
un Iterable, un Filter et un Mapper et
qui renvoie une classe implantant FunIterable
capable d'appliquer un filtre puis un mapper en une seule opération.
Les méthodes filter et map devront être optimisé pour
ne créer des FunIterable de FunIterable que si nécessaire.
Exercice 4 - Reduce [A la maison]
On souhaite ajouter une méthode
reduce appelée aussi fold, lfold suivant
les languages qui permet d'obtenir une valeur en iterant sur un iterable,
voici par exemple la définition en Python
reduce.
En fait il existe deux sortes de reduce, le reduce homogéne qui pour
un iterable sur un type va fournir un résultat du même type en utilisant une fonction
qui à deux élement de même type fait correspondre un élement de ce même type et
le reduce hétérogène qui va retourner une valeur dont le type peut être différent
du type des objets de l'iterable et qui va pour chaque élement appeler une fonction
qui prendra l'ancienne valeur et l'élement courant pour retourner une nouvelle valeur.
-
Ecrire l'interface Reducer qui correspondra à un reduce homogéne
et ajouter une méthode reduce à l'interface FunIterable.
Vous changerez les implantations en conséquence.
-
Ecrire l'interface Folder qui correspondra à un reduce hétérogène
et ajouter une méthode fold à l'interface FunIterable.
Vous changerez les implantations en conséquence.
-
Fournissez les tests Junit qui valident vos implantations.
© Université de Marne-la-Vallée