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

Examen de Java Avancé 2024 - session 1


Le but de ce TP noté est d'implanter une classe Range qui est une liste qui agit comme une vue pour les valeurs à l'intérieur d'un intervalle [start .. end[.

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 - Range

Un Range représente l'ensemble des entiers dans l'intervalle entre une valeur start (comprise) et une valeur end (non comprise). Un Range est une vue non-modifiable qui ne stocke pas les éléments entre start et end mais stocke uniquement les valeurs start et end.
Voici un exemple d'utilisation. Pour savoir si un élément est dans l'intervalle, on peut utiliser la méthode contains() :
      var range = Range.of(2, 5);
      System.out.println(range.contains(2));  // true
      System.out.println(range.contains(4));  // true
      System.out.println(range.contains(5));  // false
     

La classe Range possède les méthodes suivantes
  • une méthode of qui permet de créer un Range.
  • une méthode size qui renvoie le nombre d'éléments dans l'intervalle.
  • une méthode d'affichage qui permet de voir les éléments entre '[' et ']', séparés par des virgules.
  • une méthode permettant d'utiliser un Range dans une boucle for
              var range = ...
              for(var value : range) {
                ...
              }
             
  • l'ensemble des méthodes de l'interface List non-modifiable permettant de voir un Range comme une liste.
  • une méthode stream permettant créer un Stream sur le Range courant.
  • une méthode times qui renvoie un Gatherer qui permet de combiner chaque élément du Range avec chaque élément d'un Stream.
  • une méthode intStream permettant créer un Stream d'entiers (int) sur le Range courant.
  • une méthode asSet qui permet de voir un Range comme un Set.

Des tests unitaires correspondant à l'implantation sont ici : RangeTest.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 RangeTest.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. On souhaite que la seule façon de créer un Range soit en utilisant la méthode of(start, end). On veut de plus, que la classe Range possède une méthode size (en temps constant), ainsi qu'une méthode permettant l'affichage d'un Range (pour le format, voir ci-dessus).
    Attention, comme la taille (le résultat de la méthode size()) doit être un entier 32 bits positif, il ne doit pas être possible de créer un Range ayant une taille supérieure à un entier 32 bits positif (Integer.MAX_VALUE).
    Déclarer la classe Range ainsi que les méthodes demandées.
    Vérifier que les tests unitaires marqués Q1 passent.
    Pour la méthode d'affichage, on vous demande d'utiliser un stream.

  2. On souhaite pouvoir parcourir tous les éléments d'un Range avec la boucle for comme ceci
           var range = ...
           for(var value : range) {
             ...
           }
          

    Faites les changements qui s'imposent.
    Vérifier que les tests unitaires marqués Q2 passent.

  3. On souhaite que la classe Range soit une liste (de type java.util.List) non-modifiable.
    Faites les changements qui s'imposent.
    Vérifier que les tests unitaires marqués Q3 passent.
    Rappel : il existe une classe AbstractList.

  4. On souhaite pouvoir créer un Stream en utilisant les méthodes stream() et parallelStream() sur la classe Range.
    Dans le cas d'un Stream parallèle, on veut que si l'on a besoin de couper le Stream en deux, la coupure se fasse en plein au milieu.
    Faites en sortes que les méthodes stream et parallelStream soient implanter correctement.
    Vérifier que les tests unitaires marqués Q4 passent.
    Attention : start et end ne sont pas forcément positif !
    Note : si seul le test rangeIntStreamSortedAlot ne passe pas et que vous ne voyez pas pourquoi, vous pouvez passer à la suite.

  5. On souhaite ajouter une méthode times(function) sur un Range qui renvoie un Gatherer permettant d'appeler la fonction function avec l'élément courant d'un Stream et chaque élément du Range.
    La méthode times doit fonctionner avec des Stream de n'importe quel type d'objet et la fonction (function) prise en paramètre sait que les éléments du Range sont des entiers (primitifs).
    Voici un exemple d'utilisation.
           record Pair(int v1, int v2) {}
           var list = Range.of(0, 2).stream().gather(Range.of(0, 2).times(Pair::new)).toList();
           System.out.println(list);
              // affiche la liste des Pairs (0, 0), (0, 1), (1, 0) et (1, 1)
          

    Écrire, dans Range, la méthode times.
    Vérifier que les tests unitaires marqués Q5 passent.

  6. On souhaite ajouter une méthode intStream() qui renvoie les éléments du Range sous forme d'un Stream de type primitif.
    Écrire la méthode intStream().
    Vérifier que les tests unitaires marqués Q6 passent.
    Rappel : il existe une méthode StreamSupport.intStream(...) !

  7. Notre implantation de l'interface List n'est pas finie, en effet, certaines méthodes de List n'ont pas la bonne complexité.
    Changer l'implantation de ces méthodes pour que les tests unitaires marqués Q7 passent.

  8. En fait, la méthode subList a aussi un problème de complexité.
    Changer l'implantation de la méthode subList en faisant attention à ce que deux appels successifs à subList (range.subList(...).subList(...)) n'aient pas non plus un problème de complexité.
    Vérifier que les tests unitaires marqués Q8 passent.

  9. Enfin, on souhaite ajouter une méthode asSet() qui permet de voir un Range comme un ensemble non-modifiable.
    Écrire la méthode asSet.
    Vérifier que les tests unitaires marqués Q9 passent.