:: Enseignements :: ESIPE :: E4INFO :: 2015-2016 :: Java Avancé ::
[LOGO]

TP noté de Java Avancé


Le TP à pour but de créer différentes implantations d'une suite d'éléments manipulables au travers d'une interface Suite
Rappel, vous devez configurer le workspace d'eclipse (File > Switch WorkSpace) pour qu'il corresponde au répertoire EXAM que vous avez dans le home de votre session de TP noté.
Attention à bien lire le sujet en entier.

L'interface fr.umlv.suite.Suite représente une suite non mutable d'élements (comme java.util.List). L'interface est définie par deux méthodes
  • size qui renvoie le nombre d'élements de la suite.
    Toutes les implantations de size doivent être en temps constant.
  • get(index) qui renvoie l'élement à l'index index sachant que les élements sont rangés de 0 à size - 1.
    Pour toutes les implantations, si l'index n'est pas valide une exception IndexOutOfBoundsException doit être lancée.
Toutes les implantations de Suite ne permettent pas de stocker null et sont non-mutables.

Exercice 1 - Nice Suit(e)

Les implantations de l'interface fr.umlv.suite.Suite seront regroupées (au moins au début) dans une garbage class nommée fr.umlv.suite.SuiteImpls juste pour des questions de rangement.
Les tests JUnit pour toutes les questions du TP sont dans la classe SuiteTest.java.

  1. Avant propos, indiquer l'ensemble des méthodes de l'interface java.util.stream.Stream avec pour chaque méthode une ligne écrite en francais décrivant ce que fait la méthode.
  2. On veut implanter une méthode from dans l'interface fr.umlv.suite.Suite permettant de créer des suites en séparant les différents élements par des virgules. Par exemple,
            Suite<String> suite = Suite.from("hello", "suite");
            Suite<Integer> suite2 = Suite.from(1, 2, 3);
          

    On demande à ce que l'implantation de l'interface utilisée par from soit une classe interne nommée ElementSuite dans la classe fr.umlv.suite.SuiteImpls et que celle-ci n'utilise pas de structure de données définies dans le package java.util.
    Créer l'interface fr.umlv.suite.Suite avec les deux méthodes size et get ainsi que la méthode from.
    Attention à ce que la méthode from soit correctement paramétrée et que le compilateur ne reporte pas de warning pour cette méthode.
  3. On souhaite ajouter une méthode empty permettant de créer une suite vide, comme ceci
           Suite<String> suite = Suite.empty();
           Suite<Integer> suite2 = Suite.empty();
         
    La classe implantant une suite vide doit aussi être une classe interne de fr.umlv.suite.SuiteImpls nommée EmptySuite. Dans un but d'économiser un peu la mémoire, cette implantation ne doit pas posséder de champs et la méthode empty doit toujours renvoyer la même instance (un peu comme un singleton).
  4. On souhaite ajouter une méthode contains à l'interface Suite qui renvoie vrai si un élement pris en paramètre est dans la suite et faux sinon.
    On peut noter qu'il n'est pas nécessaire d'implanter contains dans chaque classe implantant l'interface Suite car il est possible d'implanter contains en utilisant juste les méthodes size et get.
  5. On souhaite ajouter une méthode forEach qui permet d'effectuer une action (faisant un effet de bord) sur chaque élement de la suite.
           Suite<String> suite = ...
           suite.forEach(element -> System.out.println("element " + element));
         

    Attention à ce que la signature de la méthode forEach soit la plus "générique" possible.
  6. On souhaite ajouter une méthode span à l'interface Suite pour permettre la création de suite à partir d'une taille et d'une fonction qui associe à un index, l'élement correspondant dans la suite.
    Par exemple,
           Suite<Integer> suite = Suite.span(3, x -> x * 2);
         
    correspond à la suite 0, 2, 4 c'est à dire, la suite de 3 élements dont l'élement 0 est 0 * 2, l'élement 1 est 1 * 2 et l'élement 2 est 2 * 2.
    Contrairement au deux premières implantations de l'interface Suite qui ont été écrites dans la classe SuiteImpls, cette implantation devra être écrite directement dans span sous forme d'une classe anonyme.
    Enfin, cette implantation ne doit pas stocker les élements mais recalculer l'élement à chaque fois que cela est nécessaire.
    Comme pour la méthode forEach attention à ce que la signature de la méthode soit la plus "générique" possible.
  7. En fait, il est possible de ré-implanter la méthode from en utilisant la méthode span ce qui va permettre de partager du code.
    Mettre en commentaire l'ancienne méthode from ainsi que la classe ElementSuite dans la classe SuiteImpls puis écrivez une nouvelle version de la méthode from qui utilise la méthode span.
  8. On cherche à écrire une méthode map qui fonctionne comme Stream.map, c'est à dire qui prend une fonction en paramètre et qui renvoie une Suite dont les élements sont les élements de la suite sur laquelle la méthode map est appelée auxquels on a appliqué la fonction pris en paramètre.
    Comme pour span, la suite retournée par la méthode map ne doit pas stocker les élements mais les recalculer lorsque cela est nécessaire.
    Comme pour les méthodes forEach et span, attention à ce que la signature de la méthode soit la plus "générique" possible.
  9. On peut remarquer que lorsque la suite est vide ; créée par empty ; alors la méthode map doit aussi renvoyer une suite vide. Il est donc possible "d'optimiser" un peu le code pour éviter de re-créer une suite vide.
  10. Si il vous reste encore du temps, on peut remarquer que si on appelle map sur une suite qui est elle même issue d'un map, c'est équivalent à appeler map une seule fois avec la composition des deux fonctions de chaque appel à map en argument.
    Implanter cette optimisation.
  11. En fait, il n'est pas nécessaire de faire la première question car celle-ci ne rapporte pas de point, c'est juste pour voir si vous lisez bien les sujets jusqu'au bout !