:: Enseignements :: Master :: M1 :: 2024-2025 :: Java Avancé ::
[LOGO]

TP noté de Java Avancé 2024


Le but de ce TP noté est d'implanter une vue qui se comporte comme si on insérait un tableau dans une liste, une opération habituellement appelée splice.

Vos sources Java produites pendant l'examen devront être placées sous le répertoire EXAM de votre compte ($HOME) (qui est vide dans l'environnement de TP noté). Sinon, elles ne seront pas récupérées.

Tout document papier est proscrit.
La javadoc 23 est https://igm.univ-mlv.fr/~juge/javadoc-23/.
Les seuls documents électroniques autorisés sont les supports de cours à l'url http://igm.univ-mlv.fr/~forax/ens/java-avance/cours/pdf/.

Vous avez le droit de lire le sujet jusqu'au bout, cela vous donnera une bonne idée de là où on veut aller !

Exercice 1 - SpliceView

Une SpliceView est vue qui permet de voir un tableau comme inséré au milieu d'une liste.
Par exemple, dans le code suivant avec une liste contenant trois chaînes de caractères et un tableau contenant deux chaînes de caractères
      var list = List.of("foo", "bar", "baz");
      var array = new String[] { "1", "2" };
      SpliceView<String> spliceView = SpliceView.of(list, 1, array);
     

la méthode SpliceView.of(list, start, array) créé une SpliceView qui se comporte comme si tous les éléments du tableau array étaient insérés à la position start (ici 1) de la liste.
Si on demande la taille de la SpliceView, le résultat est 5, si on demande l'élément à la position 0, le résultat est "foo", si on demande l'élément à la position 1, le résultat est "1", si on demande l'élément à la position 2, le résultat est "2", si on demande le résultat à la position 3, le résultat est "bar" et enfin, si on demande le résultat à la position 3, le résultat est "baz".
      System.out.println(spliceView.size());  // 5
      System.out.println(spliceView.get(0));  // foo
      System.out.println(spliceView.get(1));  // 1
      System.out.println(spliceView.get(2));  // 2
      System.out.println(spliceView.get(3));  // bar
      System.out.println(spliceView.get(4));  // baz
     

Si on demande l'affichage de la SpliceView, celle-ci insère un caractère '@' suivi d'un espace devant l'élément qui est à l'endroit où le tableau est inséré (le premier élément du tableau).
      System.out.println(spliceView);  // [foo, @ 1, 2, bar, baz]
     

De plus, on va vouloir que la classe SpliceView se comporte comme une liste (java.util.List) comme cela, on va pouvoir utiliser SpliceView avec toutes les méthodes qui prennent une liste en paramètre.

Des tests unitaires correspondant à l'implantation sont ici : SpliceViewTest.java
Note : comme on utilise les tests unitaires JUnit sans Maven, dans la configuration de votre projet, il faut ajouter la librairie JUnit 5, soit à partir du fichier SpliceViewTest.java, en cliquant sur l'annotation @Test et en sélectionnant le quickfix "Fixup project ...", soit en sélectionnant les "Properties" du projet (avec le bouton droit de la souris sur le projet) puis en ajoutant la librairie JUnit 5 (jupiter) au ClassPath.

  1. Dans un premier temps, on cherche à écrire la classe SpliceView avec ses méthodes size et get(index) ainsi que la méthode of(list, start, array) qui permet de créer une instance de SpliceView à partir d'une liste, d'un entier indiquant où insérer (virtuellement) le tableau et le tableau.
    La classe SpliceView est paramétrée par le type des éléments qu'elle voit. Et comme c'est une vue, la classe spliceView n'implante pas l'encapsulation et les éléments peuvent être null.
    Créer la classe SpliceView avec ses méthodes size et get et faire en sorte que la seule façon de créer une instance de SpliceView soit de passer par la méthode of().
    Vérifier que les tests unitaires marqués Q1 passent.

  2. On veut améliorer l'utilisation de la classe SpliceView, pour cela, on va faire en sorte
    • que SpliceView soit une liste non modifiable.
      Rappel, la classe AbstractList existe !
    • et qu'il soit possible de passer les éléments du tableau pris en paramètre par la méthode of() en les séparant par des virgules (en utilisant la syntaxe des varargs, les "...").
      Par exemple, on peut réécrire l'exemple de création d'un SpliceView ci-dessus, comme cela :
      var list = List.of("foo", "bar", "baz");
      SpliceView<String> spliceView = SpliceView.of(list, 1, "1", "2");
                  

    Modifier la classe SpliceView en conséquence.
    Vérifier que les tests unitaires marqués Q2 passent.
    Note : vous ne devriez pas avoir de warnings, ni utiliser @SuppressWarings !

  3. On souhaite maintenant pouvoir afficher une instance de SpliceView avec le format expliqué ci-dessus. Dans le cas où le tableau n'a pas d'élément, on n'affiche pas le "@".
    Pour cela, on vous demande dans un premier temps de faire une implantation utilisant la classe StringJoiner.
    Modifier l'implantation pour afficher SpliceView.
    Vérifier que les tests unitaires marqués Q3 passent.
    Note: ici, on présupposera qu'accéder à la liste prise à la construction avec list.get() est okay.

  4. On souhaite avoir une nouvelle implantation de la méthode d'affichage, mais en utilisant l'API des streams cette fois-ci. Commencer par mettre en commentaire le code de la méthode d'affichage écrit précédemment.
    On veut que votre stream suive le patron ci-dessous :
          return Stream.of(
              /* TODO on veut trois ou quatre streams ici,
                 le stream sur la première partie de la liste,
                 le stream sur le tableau (insérer le "@" si nécessaire),
                 le stream sur la fin de la liste
               */
            )
             .flatMap(s -> s)
             .map(/* TODO transformer les objets en String ici */)
             .collect(Collectors.joining(", ", "[", "]"));
         

    L'idée est que l'on va créer un stream de streams, le transformer en un seul stream avec flatMap puis le transformer en une chaîne de caractères avec joining.
    Vérifier que les tests unitaires utilisés précédemment fonctionnent toujours.
    Note : vous pouvez utiliser la méthode Stream.concat() qui fait la concaténation de deux streams.
    Note 2 : cette question ne vaut que 1 point, ne pas passer trop de temps dessus !

  5. Le test marqué "Q5" ne passe pas, on cherche à savoir pourquoi pour corriger votre implantation.
    Quelle est la méthode utilisée lorsque l'on parcourt une instance de SpliceView ?
    Pourquoi l'implantation actuelle est lente si la liste passée en paramètre de of est une LinkedList ?
    Modifier votre code pour que le test de "Q5" fonctionne.

  6. On veut maintenant que la classe SpliceView puisse modifier avec set(index, element) les éléments de la vue en changeant les éléments de la liste ou du tableau. Bien sûr, si l'on cherche à modifier un élément de la liste, cela ne fonctionne que si la liste est elle-même modifiable.
    Écrire la méthode set(index, element).
    Vérifier que les tests unitaires marqués Q6 passent.
    Note : attention à la valeur de retour !

  7. On voudrait être capable de modifier, d'ajouter ou retirer des éléments dans la vue. Pour cela, on va passer par le mécanisme de sous-liste (la méthode subList(from, to)) car on ne veut faire des modifications structurelles que dans certains cas.
    On souhaite
    • pouvoir modifier n'importe quel élément, c'est-à-dire le remplacer par un autre ;
    • pouvoir faire des modifications structurelles, c'est-à-dire ajouter un élément ou supprimer un élément, mais uniquement si la subList est située intégralement à droite du tableau.

    Faire en sorte que la sous-liste renvoyée par subList(from, to) ait le comportement attendu.
    Vérifier que les tests unitaires marqués Q7 passent.

  8. Pour les plus balèzes, en fait, si une sous-liste permet de voir des éléments qui ne sont pas à droite des éléments du tableau, cela ne veut pas dire qu'une de ses sous-listes (une sous-sous-liste donc) ne va pas elle, voir que les éléments à droite des éléments du tableau, auquel cas, la sous-sous-liste doit être modifiable structurellement et ces changements doivent être reflétés dans l'instance de SpliceView correspondante.
    Faire les changements qui s'imposent.
    Vérifier que les tests unitaires marqués Q8 passent.