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

Examen de Java Avancée


Le but de ce TP est d'écrire l'interface et l'implantation d'une MultiMap. Une MultiMap est une sorte table de hachage qui, pour une clé donnée, permet de stocker plusieurs valeurs différentes et garantit qu'un couple clé/valeur ne sera présent qu'une unique fois dans la structure de données.
Rappel, vous devez configurer le workspace d'eclipse (File > Switch WorkSpace) pour qu'il corresponde au répertoire EXAM présent dans le home de votre session de TP noté.
Attention à bien lire le sujet en entier.

Exercice 1 -

Les tests JUnit pour toutes les questions du TP sont dans la classe MultiMapTest.java.

  1. On cherche à créer une interface MultiMap permettant d'ajouter (add) pour un couple clé/valeur et d'obtenir (getValuesForKey) pour une clé l'ensemble des valeurs associées à celle-ci.
    En terme de structure de donnée, une MultiMap peut s'implanter sous forme d'une Map dont les valeurs sont des Set. L'orsque l'on ajoute un couple clé/valeur à la MultiMap, on cherche si il y a un Set correspondant à la clé (on le créé si ce n'est pas le cas) puis on insére la valeur à l'intérieur du Set.
    Attention a bien choisir les implantations de Map et de Set par rapport à ce qui est demandé dans le sujet !
           public class ... {
             private final ...Map<..., Set<...>> map;
             
             ...
           }
         

    Pour commencer, l'interface MultiMap devra possèder les 3 méthodes suivantes:
    • add qui ajoute un couple composé d'une clé et d'une valeur non nulles dans la MultiMap. Une même clé peut avoir plusieurs valeurs associées mais il ne peut pas y avoir deux fois la même valeur pour une même clé;
    • getValuesForKey qui renvoie l'ensemble de valeurs associées à une clé ou un ensemble vide si aucune valeur n'est associée à la clé. L'ordre des valeurs doit correspondre à l'ordre d'insertion;
    • et size qui renvoie le nombre de couples stockés dans la MultiMap.
    De plus l'interface possède une méthode create qui permet d'obtenir une implantation de l'interface.
    L'implantation de l'interface doit être dans son propre fichier séparé et ne doit pas être visible de l'extérieur.
    Exemple d'utilisation de la méthode create:
          MultiMap<String, String> multiMap = MultiMap.create();
         

    Écrire l'interface MultiMap avec les 3 méthodes add, getValuesForKey et size. Puis compléter l'interface avec la méthode create et écrire l'implantation correspondante dans un fichier séparé.
    Note: vous pouvez utiliser toutes les classes de java.util que vous souhaitez dans votre code.
    Note2: il existe une méthode computeIfAbsent sur Map qui permet de créer le Set si celui-ci n'existe pas.
  2. Ajouter une méthode d'affichage qui affiche l'ensemble des couples clé/valeurs, groupés par clé, tels que les clés et les valeurs apparaissent par ordre d'insertion.
    Par exemple, le code
          MultiMap<String, Integer> multiMap = MultiMap.create();
          multiMap.add("bar", 4);
          multiMap.add("foo", 3);
          multiMap.add("bar", 7);
          System.out.println(multiMap);
         
    affiche {bar: 4, bar: 7, foo: 3} car la clé "bar" a été ajoutée avant la clé "foo" et pour "bar", 4 a été inséré avant 7.
  3. On souhaite écrire une surcharge à la méthode create qui prend en paramètre des Map.Entry (l'interface de couple clé/valeur de Java) et créé une MultiMap stockant les couples passées en paramètre.
    Par exemple, si on utilise la méthode Map.entry() pour créer les couples, l'exemple précédent peux se ré-écrire comme ceci
          MultiMap<String, Integer> multiMap =
            MultiMap.create(Map.entry("bar", 4), Map.entry("foo", 3), Map.entry("bar", 7));
          System.out.println(multiMap);
         
    Écrire la nouvelle méthode create.
  4. Écrire une méthode forEach qui exécute une lambda pour chaque couple de la MultiMap, dans le même ordre que la méthode d'affichage.
    Par exemple
          MultiMap<String, Integer> multiMap =
            MultiMap.create(Map.entry("bar", 4), Map.entry("foo", 3), Map.entry("bar", 7));
          multiMap.forEach((key, value) -> System.out.println("key: " + key + " value: " + value));
         
    affiche
          key: bar value: 4
          key: bar value: 7
          key: foo value: 3
         
  5. Écrire une méthode addAll qui permet d'ajouter le contenu d'une MultiMap dans une MultiMap. L'ordre des éléments ajoutés dans la MultiMap doit être l'ordre d'insertion des éléments dans la MultiMap prise en paramètre.
  6. Écrire une méthode allValues() qui renvoie toutes les valeurs (pas les clés) de la MultiMap dans le même ordre que l'ordre de parcours de forEach.
    La collection renvoyée par allValues() doit agir comme une vue, donc refléter l'état de la MultiMap à chaque instant, toutes les modifications de la MultiMap postérieures à la création de la collection doivent être visibles dans cette collection. De plus, la collection renvoyée ne doit pas être modifiable si l'on passe par une des méthodes de mutation (add, remove, etc...) de la collection.
  7. En bonus, écrire une méthode asMapOfLastValues qui renvoie une java.util.Map qui agit comme une vue de la MultiMap qui, à chaque clé, associe la dernière valeur ajoutée pour cette clé. L'ordre de parcours des clés reste le même que dans la MultiMap.
    De même que la collection renvoyée par allValues(), la Map renvoyée par asMapOfLastValues doit être non-mutable, c'est à dire qu'elle ne sera pas modifiée si l'on appelle une des méthodes de mutation de l'interface Map.
    Enfin, attention à la complexité des méthodes que vous fournissez.