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

TP noté de Java Avancé


Le TP à pour but de créer une liste chaînée qui, dans la seconde partie du TP, aura la particularité d'avoir un double chaînage: le chaînage normal des éléments et un second chaînage pour les éléments qui respectent un filtre donné à la construction de la liste (un filtre est une fonction qui renvoie vrai pour un élément pris en paramètre).
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).

La classe fr.umlv.tpnote.FilteredList représente une liste chaînée d’éléments non mutables non nuls. Même si le nom de la classe fini par List, la classe n'a aucun rapport avec l'interface java.util.List. Le but du TP est de réécrire une sorte de liste chaînée. On vous demande donc de NE PAS utiliser les classes de l'API des Collections pour stocker les éléments de la FilteredList.

Exercice 1 - FilteredList

L'ensemble du code que vous allez écrire doit se trouver dans le fichier FilteredList.java. Il est interdit d'écrire du code dans un fichier auxiliaire.
Les tests JUnit pour toutes les questions du TP sont dans la classe FilteredListTest.java.

  1. Écrire une classe Entry modélisant un maillon de la liste chaînée stockant un élément ainsi qu'une référence sur l'élément suivant. Cette classe doit être non mutable.
    Dans la classe FilteredList, déclarer un champs correspondant à la tête de la liste chaînée puis écrire une méthode addFirst qui permet d'ajouter un élément devant les éléments déjà insérés (on fait un ajout en tête de la liste chaînée, si vous préférez).
    La classe FilteredList doit être paramétrée pour vérifier que le type des éléments que l'on insère est compatible.
  2. Écrire une méthode forEach qui prend en paramètre une fonction qui sera appelée sur chaque élément de la liste chaînée, dans l'ordre inverse de l'ordre des appels à addFirst.
    Par exemple,
           FilteredList<String> list = ...
           list.addFirst("foo");
           list.addFirst("bar");
           list.forEach(System.out::println);  // affiche bar puis foo
          
  3. Écrire la méthode permettant d'afficher les éléments dans le même ordre que forEach, séparés par des virgules suivies d'un espace. L'affichage de l'ensemble des éléments doit de plus être encadré par '[' et ']'.
    Avec l'exemple précédent, l'affichage sera [bar, foo].
  4. Écrire une méthode addFirstAll qui prend en paramètre une FilteredList et ajoute (avec addFirst) tous les éléments de cette liste dans la liste courante.
    PS: Si vous voulez que l'on corrige votre TP noté, levez la main et dites à voix haute "Ô capitaine, mon capitaine..." avant de démarrer le TP noté.
  5. Ajouter un nouveau constructeur qui prend en paramètre un filtre (une fonction qui prend en élément de la liste en paramètre et qui renvoie un booléen). Puis écrire une méthode filtered qui renvoie une nouvelle FilteredList contenant les éléments pour lesquels le filtre renvoie vrai.
    La FilteredList renvoyée est elle-même non-filtrée.
    Attention: l'ordre des éléments dans la FilteredList renvoyée doit être le même que l'ordre des éléments dans la liste sur laquelle on appelle la méthode filtered.
    Aide: l'intérêt d'une méthode récursive est que l'on peut faire des choses après l'appel récursif, lorsque l'on remonte.
    Note: Il faut garder l'ancien constructeur, sinon les tests des questions précédentes ne passeront plus.
    Note 2: Si vous ne voyez pas comment faire, vous pouvez utiliser une structure intermédiaire mais vous n'aurez pas tous les points à la question !
  6. On souhaite écrire une méthode filteredForEach qui, comme forEach appelle la fonction passée en paramètre mais uniquement avec les éléments pour lesquels le filtre passé à la construction renvoie vrai.
    Comme on connaît le filtre à la construction de la liste, au lieu de tester le filtre lors du parcours dans filteredForEach, on peut construire un second chaînage liant uniquement les éléments pour lesquels le filtre est vrai.
    Par exemple, avec un filtre qui ne garde que les éléments pairs, si la liste contient 2, 3, 4, et 5, on obtient les chaînages suivant

    Ajouter le second chaînage en modifiant les classes FilteredList, Entry et la méthode addFirst, puis écrivez le code de la méthode filteredForEach.
    Bonus: il est possible de partager une partie du code entre forEach et filteredForEach.
  7. Maintenant qu'un deuxième chaînage a été ajouté, écrire une nouvelle version de la méthode filtered (en mettant en commentaire l'ancien code), qui utilise directement ce second chaînage.
    Bonus: on peut écrire la méthode filtered sans dupliquer les éléments de la liste chaînée.
  8. On souhaite que le code suivant fonctionne. On traite les mêmes éléments que la méthode forEach (dans le même ordre).
          FilteredList<String> list = ...
          for(String element: list) { 
            ...
          }
         
    Faîtes les changements qui s'imposent.
  9. Il est possible de simplifier le code de la fonction d'affichage pour utiliser un Stream à la place du code que vous avez écrit précédemment. Commenter le code précédent et écrire un nouveau code utilisant un Stream pour générer la représentation en chaîne de caractères.
    Utilisez la méthode Stream.iterate qui prend 3 paramètres.