:: Enseignements :: Master :: M1 :: 2023-2024 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Examen intermédiaire de Java Avancé 2023 |
Le but de ce TP noté est d'implanter une classe Cord (une corde) qui un conteneur mutable d'objets
qui permet de voir les éléments en ordre inverse de leur ordre d'insertion (comme une pile) et que l'on peut
attacher à une autre corde.
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.
Comme nous utilisons Java 21 donc vous devez configurer votre Eclipse pour cela :
Dans Window > Preferences > Java > Installed JREs: vous devez ajouter Java 21 qui est disponible sur vos machines
dans le répertoire /usr/local/apps/java21
Dans Window > Preferences > Java >Compiler le niveau compiler compliance level doit être 21.
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 - Cord
Cord est une classe paramétrée par le type des éléments que l'on va stocker dedans.
Les éléments ne peuvent pas être
null.
-
La classe Cord possède un constructeur sans paramètre.
-
La méthode add permet d'ajouter un élément en haut de la corde.
-
La méthode get(index) permet d'accéder à l'élément à l'index pris en paramètre.
L'index 0 correspond au dernier élément inséré (celui du haut), l'index 1 correspond à l'avant-dernier
élément inséré, etc.
-
La méthode forEachIndexed(function) appelle la méthode function
avec l'index de l'élément et l'élément lui-même pour tous les éléments dans le même ordre
que get(index), donc dans l'ordre inverse que l'ordre d'insertion.
-
La méthode createChild permet de créer une nouvelle corde fille.
Une corde fille accède à ses éléments (en sens inverse) suivi des éléments de la corde mère (eux aussi
en sens inverse).
Donc, lors d'un appel à get() ou forEachIndexed, on cherche d'abord dans les éléments
de la corde courante puis dans les éléments de la corde mère.
-
Il doit être possible de parcourir une corde (et ses cordes mères) avec une boucle
for.
-
La méthode attachParent permet d'attacher une corde mère à une corde n'ayant pas
déjà une corde mère.
-
La méthode indexedElements permet de voir les éléments (et leur index) sous forme
d'un Stream.
Voici des exemples d'utilisation
Cord<Integer> cord = new Cord<Integer>();
cord.add(3);
cord.add(17);
System.out.println(cord.get(0)); // 17
System.out.println(cord.get(1)); // 3
On peut remarquer que
get() renvoie les valeurs dans
l'ordre inverse de l'ordre d'insertion (l'ordre d'appel des
méthodes
add).
parent.forEachIndexed((index, element) -> {
System.out.println(index + " " + element);
}); // 0 17
// 1 3
De même,
forEachIndexed() appelle la lambda avec les éléments dans l'ordre
inverse de l'ordre d'insertion.
Cord<Integer> child = cord.createChild();
child.add(116);
System.out.println(child.get(0)); // 116
System.out.println(child.get(1)); // 17
System.out.println(child.get(2)); // 3
La méthode
createChild crée une corde fille
child
qui peut accéder à ses propres éléments et à ceux de la corde mère (ici
cord).
De plus, si on ajoute un élément à la corde mère (ici
cord), la modification sera visible dans la cord fille.
cord.add(8234);
for(int element : child) {
System.out.println(element);
} // 116
// 8234
// 17
// 3
Faire une boucle sur une corde parcourt (toujours dans l'ordre inverse de l'ordre d'insertion) les cordes filles avant les cordes mères.
Des tests unitaires correspondant à l'implantation sont ici :
CordTest.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
CordTest.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.
-
On souhaite créer la classe Cord avec un constructeur sans paramètre.
En terme d'implantation, une corde doit stocker ses éléments dans une liste (java.util.List) implantée
avec un tableau dynamique (qui s'agrandit tout seul lorsque c'est nécessaire).
On souhaite de plus créer les les méthodes add et get(index) qui permettent respectivement
d'ajouter un élément à la fin et d'accéder un élément à un index (en partant de la fin,
l'index 0 correspond au dernier élément).
Écrire la classe Cord et ses méthodes add et get(index).
Vérifier que les tests marqués "Q1" passent.
Note : si cela vous aide, il existe une méthode reversed() sur l'interface java.util.List.
-
On souhaite écrire une méthode forEachIndexed(function) qui prend en paramètre
une fonction avec deux paramètres et appelle celle-ci avec l'index et l'élément
de chaque élément de la corde. Comme avec get, l'ordre des éléments est
l'ordre inverse de l'ordre d'insertion.
Écrire la méthode forEachIndexed.
Vérifier que les tests marqués "Q2" passent.
Note : éviter le boxing inutile SVP !
-
On souhaite écrire une méthode createChild qui crée une nouvelle corde fille
à laquelle on attache la corde courante (celle sur laquelle on a appelée la méthode createChild) qui devient sa mère.
On souhaite de plus, changer le code de get(index) pour que cette méthode
permette d'accéder aux éléments de la corde courante puis aux éléments de la corde mère,
et de la corde mère de la corde mère, etc... (cf. exemple plus haut).
Modifier le code de le classe Cord pour ajouter la méthode createChild.
Vérifier que les tests marqués "Q3" passent.
Note : on ne vous demande pas de mettre à jour l'implantation de forEachIndexed,
pour l'instant.
Note 2 : si le code de get() est récursif, vous aurez beaucoup de mal à faire les questions suivantes.
-
On souhaite maintenant mettre à jour la méthode forEachIndexed (comme
pour la méthode get() à la question précédente) afin de parcourir aussi les éléments de la corde mère.
Vérifier que les tests marqués "Q4" passent.
-
On souhaite pouvoir parcourir une corde (et ses cordes mère, grand-mère, etc) en utilisant
la boucle "for" de Java comme dans l'exemple ci-dessus.
Pour l'instant, on va supposer qu'une corde a toujours au moins un élément.
Modifier le code de Cord pour pouvoir parcourir les éléments
avec une boucle "for".
Vérifier que les tests marqués "Q5" passent.
-
Si vous êtes balèzes, modifier votre code pour que le parcours fonctionne aussi dans le cas où une corde
(ou une corde mère, etc) est vide. Sinon, passer à la question suivante.
Vérifier que les tests marqués "Q6" passent.
-
On souhaite ajouter une méthode attachParent(parent) qui permet d'attacher
une corde mère à la corde courante, si la corde courante n'a pas déjà une corde mère.
Écrire la méthode attachParent.
Vérifier que les tests marqués "Q7" passent.
-
En fait, la méthode attachParent introduite précédemment a un problème,
elle permet de créer, si on suit les cordes mères, des cycles où l'on retombe
sur la corde initiale.
On se propose de détecter ce cas et d'empêcher l'attachement dans ce cas.
Changer le code de attachParent pour détecter les cycles.
Vérifier que les tests marqués "Q8" passent.
-
Enfin, on souhaite créer une méthode indexedElements qui renvoie
un Stream d'objets ayant deux méthodes index() qui renvoie l'index de l'élément
et element qui renvoie l'élément dans le même ordre que forEachIndexed.
On ne vous demande pas ici, d'implanter votre propre Stream, car nous n'avons pas encore
vu en cours comment faire, mais d'utiliser les méthodes que nous avons déjà vues pour créer
le Stream.
Écrire la méthode indexedElements().
Vérifier que les tests marqués "Q9" passent.
Indice : on peut utiliser mapMulti() pour propager les valeurs de forEachIndexed.
© Université de Marne-la-Vallée