Série 8 - Jokers et fabriques

Jokers

Comme vu au cours, les jokers (ou wildcards) permettent, entre autres, de généraliser le type des paramètres de certaines méthode génériques. Ainsi, une méthode addAll qui ajoute à la liste à laquelle on l'applique tous les éléments de la liste reçue en argument peut être définie ainsi :

interface List<E> {
    // ...
    void addAll(List<? extends E> other);
}

Comparée à une version prenant une liste de type List<E> en argument, celle-ci est plus générale puisqu'elle permet, p.ex., l'appel suivant :

List<Number> l = new LinkedList<>();
List<Integer> li = new LinkedList<>();
li.add(1);
l.addAll(li);

Cet appel serait invalide si addAll prenait un argument de type List<E>. Pour plus de détails, voir le cours.

Afin de vous entraîner à utiliser les jokers, nous vous fournissons une archive zip contenant un fichier Lists.java définissant une classe Lists (notez le s à la fin !) qui offre trois méthodes statiques travaillant sur les listes Java :

  1. addMultipleOccurrences, qui ajoute un certain nombre d'occurrences d'un élément à la fin d'une liste,
  2. copy, qui copie le contenu d'une première liste à la fin d'une seconde liste,
  3. max, qui retourne le plus grand élément d'une liste selon un comparateur reçu en argument.

Nous vous fournissons de plus un test JUnit pour cette classe dans le fichier ListsTest.java. Ce test comporte 13 appels aux trois méthodes sus-mentionnées, numérotés par des commentaires. Dans la version que nous vous fournissons, tous ces appels sont signalés comme erronés par Eclipse.

Examinez chacun de ces 13 appels et déterminez s'il pourrait être valide ou non. Si oui, généralisez le type de la fonction appelée (dans la classe Lists) au moyen de jokers. Si non, mettez l'appel en commentaire et justifiez votre choix. Attention, vous n'avez pas le droit de modifier le code des fonctions de Lists, seulement le type de leurs arguments et variables locales.

Fabrique abstraite

Le premier exercice de l'examen intermédiaire consistait à écrire une classe modélisant un index inversé. Dans le corrigé de l'examen, cet index était mis en œuvre au moyen d'une table associative (de type HashMap) contenant des ensembles (de type HashSet) comme valeurs. Le but de cet exercice est de modifier, selon les instructions ci-dessous, une variante du code du corrigé que nous vous fournissons dans une archive zip, accompagnée d'autres classes décrites plus loin.

Etant donné que la bibliothèque Java fournit d'autres mises en œuvre des tables associatives et des ensembles que HashMap et HashSet (en particulier TreeMap et TreeSet), il peut être intéressant de pouvoir choisir lesquelles utiliser pour l'index inversé. Le premier but de cet exercice est donc de modifier la classe ConcreteInvertedIndex que nous vous fournissons pour que son constructeur prenne en argument une fabrique abstraite permettant de créer des tables associatives de type Map et des ensembles de type Set. Cette fabrique doit être utilisée pour créer la totalité des tables et ensembles dont l'index inversé a besoin.

Une fois cette modification apportée, vous pouvez en faire usage pour comparer le temps nécessaire à la construction et à la consultation d'un index inversé de belle taille en utilisant les différentes mises en œuvre des tables associatives et des ensembles mentionnées ci-dessus. Pour ce faire, nous vous fournissons les classes RandomDocument et InvertedIndexBenchmarker. La première modélise des documents au contenu aléatoire tandis que la seconde place dans un index inversé 150 documents de ce type, de 7000 mots chacun, avant de l'utiliser pour trouver les mots apparaissant dans la totalité des documents. Elle mesure et affiche le temps nécessaire à l'opération.

Relevez le temps donné en utilisant HashMap puis TreeMap comme mises en œuvre de l'interface Map, et HashSet puis TreeSet comme mises en œuvre de l'interface Set. Dans chacun des quatre cas, lancez plusieurs fois le programme pour voir à quel point les temps affichés sont stables.

Quelles conclusions tirez-vous des performances relatives de HashMap et HashSet comparé à TreeMap et TreeSet, pour cet exemple ? Et que pouvez-vous dire quant à la facilité de mesurer les performances d'un programme Java ?

Michel Schinz – 2013-05-03 16:40