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

TP noté de Java Avancé


Ce TP a pour but de créer une structure de données Container qui stocke des éléments dans un tableau (dynamique) en utilisant une fonction de projection prise en paramètre à la création d'un Container.
Une fonction de projection est une fonction qui prend en paramètre un élément et renvoie un entier; lorsque l'on stocke un objet dans le Container, on appelle la fonction de projection sur l'objet que l'on veut stocker et celle-ci renvoie l'indice du tableau qui contiendra l’élément.
Le mécanisme de stockage utilisant une fonction de projection ressemble un peu à l'ajout dans une table de hachage avec une fonction de hachage, à ceci près que la fonction de projection devrait renvoyer une valeur différente pour chaque objet à stocker: il ne peut pas y avoir de collision. Cela veut dire que, lors de l'ajout, si la fonction de projection renvoie une valeur négative ou un indice qui correspond à une case déjà occupée, c'est une erreur (dans les deux cas).
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 (si si, vraiment).
JAVADOC.

Vous allez écrire la classe fr.umlv.irig.Container qui implante cette structure de données.

Exercice 1 - Container

L'ensemble du code de la structure de données doit se trouver dans le fichier Container.java. Il est interdit d'écrire du code dans un fichier auxiliaire.
La classe Container doit être paramétrée et ne pas permettre de stocker null.
Les tests JUnit pour toutes les questions du TP sont dans la classe ContainerTest.java.

  1. Écrire le constructeur de Container qui prend en paramètre la fonction de projection. Pour cela, posez-vous la question de la signature de la fonction de projection ... et, ô miracle, c'est un type de fonction déjà présent dans le JDK. Donc, utilisez le type du JDK.
    Écrire la méthode add qui ajoute un élément à l'indice donné par la fonction de projection. Faite attention à gérer correctement l'ensemble des cas d'erreurs.
    Écrire une méthode size qui renvoie le nombre d'élément présents dans la structure de données.
    Remarque: vous êtes libres de gérer la taille du tableau dynamique comme bon vous semble, mais n'oubliez pas que les tests unitaires peuvent vous guider.
  2. Écrire une méthode contains qui renvoie vrai si et seulement si un élément est déjà présent dans le structure de données. Pourquoi cette méthode ne prend pas un Object en paramètre comme les collections de java.util ?
  3. Écrire une méthode forEach qui parcourt les éléments de la structure de données en ordre croissant des indices. La méthode forEach prend en paramètre une fonction qui prend en paramètre un élément du Container et provoque un effet de bord.
  4. Écrire une méthode toString qui permet d'afficher les éléments contenus dans la structure de données en ordre croissant de leurs indices. Les éléments sont séparés par des virgules (suivies d'un espace) et l'ensemble des éléments est donné entre accolades.
    Par exemple,
          Container<String> c = new Container<>(String::length);
          c.add("hello");
          c.add("world!");
          System.out.println(c);   // affiche {hello, world!}
         

    On peut noter que l'ordre de parcours de forEach et l'ordre d'affichage dans toString sont le même.
  5. Écrire une méthode iterator qui renvoie un itérateur sur les éléments dans le même ordre que l'ordre de parcours de forEach.
    Vérifier avec la javadoc des méthodes hasNext et next que vous implantez l'itérateur correctement.
  6. Implanter la méthode remove de l'itérateur.
    De même, vérifier que la méthode remove est correctement écrite en regardant sa javadoc.
  7. Écrire une méthode asSafeCollection qui renvoie une collection qui montre les éléments du Container comme une Collection. Dans un premier temps, on va se contenter de voir les éléments du Container comme une Collection sans permettre de demander des modifications de celle-ci.
    La méthode asSafeCollection prend en paramètre un objet de type java.lang.Class qui correspond à la classe des éléments stockés dans le Container. Ce paramètre ne sert à rien pour cette question.
    Note: il existe des classes qui commencent par Abstract* dans java.util.
  8. Implanter la méthode add de la collection renvoyée par l'appel à asSafeCollection en ajoutant l'élément au Container après avoir vérifié que que la classe de l'élément est bien compatible avec le paramètre de la méthode asSafeCollection. Dans le cas contraire, une exception ClassCastException doit être levée.
  9. Implanter la méthode contains de la collection renvoyée par l'appel à asSafeCollection. Que doit-on faire si l'élément n'est pas de la bonne classe ?
  10. Bonus (à faire uniquement si tout le reste fonctionne parfaitement): Implanter la méthode addAll qui permet d'ajouter plusieurs éléments à la Collection renvoyée par l'appel à asSafeCollection.
    Ici, il y a une astuce, dans le cas où la collection a été créée par asSafeCollection sur un Container qui possède la même fonction de projection (mais ce n'est pas forcément le même Container) et avec le même type d'éléments. Il est possible d'optimiser car il n'est pas nécessaire de rappeler la fonction de projection (comme c'est la même) pour insérer les éléments de la collection prise en paramètre.
    Il y a une deuxième astuce qui est que l'on peut pré-calculer la taille du tableau résultant pour éviter de l’agrandir à chaque fois que l'on ajoute un élément.
    Ici, on ne vous fournit pas les tests... pas parce qu'on ne les a pas, mais parce que sinon, ce n'est pas drôle. Il faut donc écrire vos propres tests.