:: Enseignements :: ESIPE :: E4INFO :: 2020-2021 :: Java Avancé ::
![[LOGO]](http://igm.univ-mlv.fr/ens/resources/mlv.png) | Examen de Java Avancé |
Le but de ce TP noté est d'implanter une structure de données appelée TaggedBuffer
qui permet d'indiquer que certains de ses éléments sont importants (tagged) et d'autres pas.
Un TaggedBuffer offre la possibilité de voir soit tous ses éléments, soit uniquement ceux qui sont importants. Pour cela, les opération définies sur un TaggedBuffer sont paramétrées
par un booléen qui indique si il faut considérer uniquement les éléments importants ou non.
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.
Vous pouvez consulter la javadoc à travers Eclipse (onglet Javadoc), en utilisant
jdoc dans un terminal
Sinon la doc est là:
/usr/local/apps/java15/docs/api/index.html.
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 - GapBuffer
La classe
TaggedBuffer est un conteneur d'éléments muni d'une fonction qui
indique, pour chaque élément, si celui-ci est important ou non.
La fonction prend donc en paramètre un élément et renvoie un booléen
true
si l'élément est important ou
false si l'élément n'est pas important.
La fonction, prise à la construction, doit être
consistente,
c'est à dire toujours renvoyer la même valeur (
true ou
false)
pour un même élément.
La classe
TaggedBuffer possède les opérations suivantes :
-
add(element) qui permet d'ajouter un élément.
-
size(boolean onlyTagged) qui indique le nombre d'éléments
(en considérant uniquement les éléments importants si onlyTagged est vrai)
-
findFirst(boolean onlyTagged) qui renvoie le premier élément.
(en considérant uniquement les éléments importants si onlyTagged est vrai)
-
forEach(boolean onlyTagged, ...) qui permet de parcourir les éléments.
(en considérant uniquement les éléments importants si onlyTagged est vrai)
-
iterator(boolean onlyTagged) qui renvoie un itérateur pour cette structure de données.
(en considérant uniquement les éléments importants si onlyTagged est vrai)
-
asTaggedList() qui renvoie une liste des éléments importants.
-
stream(boolean onlyTagged) qui renvoie un Stream des éléments.
(en considérant uniquement les éléments importants si onlyTagged est vrai)
La classe TaggedBuffer est paramétrée par le type des éléments qu'elle contient et
ces éléments ne peuvent pas être null.
Attention, lorsque l'on appelle une des méthodes qui prend onlyTagged en paramètre avec la valeur false,
alors la fonction qui indique si un élement est important ou pas ne doit pas être appelée.
Voici un exemple d'utilisation de la classe
TaggedBuffer.
var buffer = new TaggedBuffer<Integer>(i -> i % 2 == 0);
buffer.add(1);
buffer.add(2);
buffer.add(3);
buffer.add(5);
System.out.println(buffer.size(true)); // 1
System.out.println(buffer.size(false)); // 4
La première ligne crée un
TaggedBuffer avec une fonction qui considère tous les nombres
pairs (les nombres divisibles par 2) comme importants.
Donc la valeur 2 est une valeur importante, tandis que les valeurs 1, 3 et 5 ne sont pas
des valeurs importantes.
Lorsque l'on demande la taille en considérant uniquement les éléments importants :
size(true), alors la taille est 1 car seul le nombre 2 est important. Lorsque l'on demande la taille en considérant tous les éléments :
size(false), la taille est 4.
-
On souhaite créer la classe TaggedBuffer avec le constructeur et les méthodes add
et size.
-
Les éléments doivent être stockés dans un tableau (pas une liste !!)
-
Pour l'instant, votre implantation n'aura pas plus de 4 éléments.
-
la méthode size doit avoir une implantation
en temps constant (sans parcourir les éléments si vous préférerez).
Vérifier que les tests unitaires marqués "Q1" passent.
-
Modifier le code pour permettre permettre à votre implantation de supporter
un nombre arbitraire d'éléments en agrandissant la taille du tableau d'un facteur 2
(toujours en commençant avec une taille de 4 par défaut)
lorsque le tableau est plein.
Vérifier que le test unitaire marqué "Q2" passe.
-
On souhaite écrire une méthode findFirst qui renvoie le premier élément du
TaggedBuffer. Si le paramètre onlyTagged est vrai, on considère uniquement les éléments importants, et sinon, on considère tous les éléments (important ou non).
Il faut aussi gérer le fait qu'il peut ne pas y avoir de premier élément à considérer.
Écrire la méthode findFirst(boolean onlyTagged) et
vérifier que les tests unitaires marqués "Q3" passent.
-
On souhaite écrire une méthode forEach qui en plus du booléen indiquant
si l'on doit considérer uniquement les éléments importants, prend en second paramètre une fonction
qui est appelée avec chaque élément à considérer du TaggedBuffer.
Les éléments doivent être appelés dans le même ordre que l'ordre d'insertion dans le TaggedBuffer.
Écrire la méthode forEach et
vérifier que les tests unitaires marqués "Q4" passent.
-
On souhaite maintenant écrire une méthode iterator qui, comme les méthodes précédentes,
prend en paramètre un booléen indiquant si l'on doit considérer uniquement les éléments importants
ou non et renvoie un itérateur permettant de parcourir les éléments considérés du TaggedBuffer
dans l'ordre d'insertion.
Si l'on ajoute des éléments dans le TaggedBuffer après l'appel à la méthode iterator,
ceux-ci ne doivent pas être visibles par l'itérateur renvoyé précédemment.
Écrire la méthode iterator(boolean onlyTagged) et
vérifier que les tests unitaires marqués "Q5" passent.
Note 1 : On peut remarquer que l'on connaît à l'avance le nombre d'éléments que l'on va parcourir,
donc il y a une façon simple (mais ce n'est pas la seule) d'écrire le test permettant de savoir si il reste encore des éléments dans l'itérateur.
Note 2 : En terme d'implantation, on vous demande d'écrire votre itérateur sous forme d'une
classe anonyme. Tout autre implantation sera considérée comme hors sujet.
-
On souhaite maintenant écrire une méthode asTaggedList qui renvoie une liste
non modifiable des éléments qui sont importants.
L'accès à un élément en utilisant cette liste doit se faire en temps constant.
Si l'on ajoute des éléments dans le TaggedBuffer après l'appel à la méthode asTaggedList,
ceux-ci ne doivent pas être visibles par la liste renvoyée précédemment.
On ne souhaite pas directement stocker les éléments dans la liste car
cela ferait plus de travail pour le Garbage Collector (il doit suivre toutes les références).On va donc plutôt stocker un tableau des index des éléments qui sont importants.
Par exemple, avec le code suivant
var buffer = new TaggedBuffer<String>(s -> s.charAt(0) != 'b');
buffer.add("booz"); // index 0
buffer.add("bar"); // index 1
buffer.add("foo"); // index 2
buffer.add("baz"); // index 3
buffer.add("whizz"); // index 4
Les éléments "foo" et "whizz" sont importants (car ils ne commencent pas par 'b')
donc le tableau des index est [2, 4]
car ce sont les valeurs d'index des éléments "foo" et "whizz".
Écrire la méthode asTaggedList et
vérifier que les tests unitaires marqués "Q6" passent.
Note : il existe une classe java.util.AbstractList !
-
On souhaite écrire une méthode stream qui prend en paramètre un booléen
indiquant si l'on doit considérer uniquement les éléments importants ou non et
renvoie un Stream de ces éléments.
Pour cela, on vous demande d'écrire un Spliterator sous-jacent.
L'ordre des éléments dans le Stream doit être l'ordre d'insertion.
Si l'on ajoute des éléments dans le TaggedBuffer après l'appel à la méthode stream,
ceux-ci ne doivent pas être visibles par le Stream renvoyé précédemment.
Pour cette question, on va pour l'instant se limiter à une implantation d'un Spliterator
qui ne sait pas se couper en deux.
Écrire la méthode stream(boolean onlyTagged) et
vérifier que les tests unitaires marqués "Q7" passent.
-
Enfin, on souhaite finir l'implantation du Spliterator en ajoutant
le support des Stream parallèles.
Modifier votre implantation en conséquence et
vérifier que les tests unitaires marqués "Q8" passent.
Note : on peut remarquer que suivant si l'on considère uniquement les éléments importants ou non,
les caractéristiques du Spliterator ne sont pas les mêmes.
© Université de Marne-la-Vallée