Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • enonce
  • master
2 results

Target

Select target project
No results found
Select Git revision
  • master
1 result
Show changes

Commits on Source 13

151 files
+ 12581
59
Compare changes
  • Side-by-side
  • Inline

Files

Original line number Diff line number Diff line
#Mon Sep 09 10:51:55 CEST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Original line number Diff line number Diff line
package fr.univamu.progav;

import fr.univamu.progav.td2.DebuggerTutorial;
import fr.univamu.progav.td.td2.DebuggerTutorial;

public class Main {

Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class BreadthFirstSearchV1 {

  // Méthode pour le parcours en largeur (par niveau) d'un arbre.
  // La méthode doit afficher chaque élément, de haut (la racine) en bas,
  // chaque niveau de gauche à droite.
  public BreadthFirstSearchV1(Tree root) {
    List<Tree> currentLevel = new ArrayList<>();
    currentLevel.add(root);
    while (!currentLevel.isEmpty()) {
      List<Tree> nextLevel = new ArrayList<>();
      for (Tree tree : currentLevel) {
        System.out.print(tree.getValue() + " ");
        for (Tree child : tree.getChildren()) {
           nextLevel.add(child);
        }
      }
      currentLevel = nextLevel;
      System.out.println();
    }
  }

  // Problème :
  // La méthode est difficile à comprendre
  // Solution proposée :
  // remplacer les boucles internes par des appels à de nouvelles méthodes

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class BreadthFirstSearchV2 {

  // extraction de la boucle la plus imbriquée, qui devient la méthode addAllChildren
  public BreadthFirstSearchV2(Tree root) {
    List<Tree> currentLevel = new ArrayList<>();
    currentLevel.add(root);
    while (!currentLevel.isEmpty()) {
      List<Tree> nextLevel = new ArrayList<>();
      for (Tree tree : currentLevel) {
        System.out.print(tree.getValue() + " ");
        addAllChildren(tree, nextLevel);
      }
      currentLevel = nextLevel;
      System.out.println();
    }
  }

  private static void addAllChildren(Tree tree, List<Tree> nextLevel) {
    for (Tree child : tree.getChildren()) {
       nextLevel.add(child);
    }
  }


  // Problème :
  // on peut extraire la boucle 'for' sur 'tree', mais cela donne
  // une méthode difficile à nommer ('displayCurrentLevelAndComputeNextLevel' ?)
  // Solution :
  // Séparer la boucle en deux boucles, une pour l'affichage, une pour le calcul
  // du niveau suivant.
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class BreadthFirstSearchV3 {

  // la boucle interne 'for' fait deux choses :
  // - afficher les éléments du niveau;
  // - préparer le prochain niveau.
  // La prochaine étape de refactoring consiste à séparer
  // les deux fonctionnalités, pour que chacune soit gérée par sa propre boucle.
  // Cela permettra l'extraction de deux méthodes ensuite.
  public BreadthFirstSearchV3(Tree root) {
    List<Tree> currentLevel = new ArrayList<>();
    currentLevel.add(root);
    while (!currentLevel.isEmpty()) {
      // Affichage des éléments du niveau
      for (Tree tree : currentLevel) {
        System.out.print(tree.getValue() + " ");
      }
      // Préparation du prochain niveau
      List<Tree> nextLevel = new ArrayList<>();
      for (Tree tree : currentLevel) {
        addAllChildren(tree, nextLevel);
      }
      currentLevel = nextLevel;
      System.out.println();
    }
  }

  private static void addAllChildren(Tree tree, List<Tree> nextLevel) {
    for (Tree child : tree.getChildren()) {
       nextLevel.add(child);
    }
  }

  // Problème :
  // le constructeur est trop complexe.
  // Solution :
  // On extrait le contenu du 'while' dans deux nouvelles méthodes.

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class BreadthFirstSearchV4 {

  // On extrait les deux tâches de la boucle 'while' en deux méthodes dédiées.
  public BreadthFirstSearchV4(Tree root) {
    List<Tree> currentLevel = new ArrayList<>();
    currentLevel.add(root);
    while (!currentLevel.isEmpty()) {
      printLevel(currentLevel);
      currentLevel = getNextLevel(currentLevel);
      System.out.println();
    }
  }

  private static List<Tree> getNextLevel(List<Tree> currentLevel) {
    List<Tree> nextLevel = new ArrayList<>();
    for (Tree tree : currentLevel) {
      addAllChildren(tree, nextLevel);
    }
    return nextLevel;
  }

  private static void printLevel(List<Tree> currentLevel) {
    for (Tree tree : currentLevel) {
      System.out.print(tree.getValue() + " ");
    }
  }

  private static void addAllChildren(Tree tree, List<Tree> level) {
    for (Tree child : tree.getChildren()) {
       level.add(child);
    }
  }

  // Conclusion :
  // chaque méthode contient une seule boucle, fait une seule chose, et
  // est bien nommée. C'est une solution satisfaisante.
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.Scanner;

public class InteractiveSumV1 {

  private final Scanner input;

  public InteractiveSumV1() {
    this.input = new Scanner(System.in);
  }

  public InteractiveSumV1(Scanner scanner) {
    this.input = scanner;
  }

  // Sommer tous les entiers lisibles jusqu'à lire l'entier -1,
  // auquel cas on s'arrête.
  public void run() {
    System.out.println("Entrez des entiers (-1 pour terminer).");
    int sum = 0;
    boolean isNotOver = true;
    while (isNotOver) {
      int value = input.nextInt();
      if (value == -1) {
        isNotOver = false;
      } else {
        sum = sum + value;
      }
    }
    System.out.println("Somme = " + sum);
  }

  // Problème :
  // l'utilisation d'une variable booléenne pour contrôler la terminaison de
  // la boucle est peu lisible (séparation entre le 'while' qui décide de la continuation, et le
  // 'if' qui effectue le test de continuation).
  // Solution :
  // déplacer le test d'égalité directement dans la condition du 'while'.
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.Scanner;

public class InteractiveSumV2 {

  private final Scanner input;

  public InteractiveSumV2() {
    this.input = new Scanner(System.in);
  }

  public InteractiveSumV2(Scanner scanner) {
    this.input = scanner;
  }

  // Suppression de la variable booléenne contrôlant la terminaison de la boucle.
  // On teste directement 'value', mais il faut l'initialiser avant le 1er test.
  public void run() {
    System.out.println("Entrez des entiers (-1 pour terminer).");
    int sum = 0;
    int value = input.nextInt();
    while (value != -1) {
      sum = sum + value;
      value = input.nextInt();
    }
    System.out.println("Somme = " + sum);
  }

  // Problème :
  // l'affectation 'value = input.nextInt()' est répétée.
  // Solution :
  // privilégier l'usage de 'break' pour quitter une boucle en cours d'itération.

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.Scanner;

public class InteractiveSumV3 {

  private final Scanner input;

  public InteractiveSumV3() {
    this.input = new Scanner(System.in);
  }

  public InteractiveSumV3(Scanner scanner) {
    this.input = scanner;
  }

  // le 'while(true)' signale clairement une boucle qui se
  // quitte par un 'break' ou 'return'. La condition est testée
  // juste avant de quitter la boucle.
  public void run() {
    System.out.println("Entrez des entiers (-1 pour terminer).");
    int sum = 0;
    while (true) {
      int value = input.nextInt();
      if (value == -1) break;
      sum = sum + value;
    }
    System.out.println("Somme = " + sum);
  }

  // Conclusion :
  // ordre naturel des instructions, pas de répétition.
  // Dans la version suivante, on change les règles :
  // 0 termine le programme,
  // les nombres négatifs doivent être ignorés.

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.Scanner;

public class InteractiveSumV4 {

  private final Scanner input;

  public InteractiveSumV4() {
    this.input = new Scanner(System.in);
  }

  public InteractiveSumV4(Scanner scanner) {
    this.input = scanner;
  }

  // On modifie la règle : on somme les positifs et on s'arrête à 0.
  // On utilise 'continue' pour passer à l'itération suivante. Si 'value' est
  // négatif, l'affectation à 'sum' est ainsi sautée.
  public void run() {
    System.out.println("Entrez des entiers (-1 pour terminer).");
    int sum = 0;
    while (true) {
      int value = input.nextInt();
      if (value == 0) break;
      if (value < 0) continue;
      sum = sum + value;
    }
    System.out.println("Somme = " + sum);
  }

  // Conclusion :
  // cette solution est un peu plus simple que d'avoir mis
  // l'affectation 'sum = sum + value' dans un 'if'. On met en valeur que
  // le comportement normal est de sommer les valeurs, et que la règle de
  // sauter les négatifs est une exception.

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

public class Main {

  public static void main(String[] args) {
//    new BreadthFirstSearchV1(Tree.getSampleTree());

//    List<Integer> primes = SieveV1.allPrimes(100);
//    primes.forEach(System.out::println);

    new InteractiveSumV1().run();
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class SieveV1 {

  // calcul de tous les nombres premiers jusqu'à 'max'
  public static List<Integer> allPrimes(int max) {
    List<Integer> primes = new ArrayList<>();
    for (int n = 2; n <= max; n++) {
      boolean isPrime = true;
      for (Integer prime : primes) {
        if (n % prime == 0) {
          isPrime = false;
        }
      }
      if (isPrime) {
        primes.add(n);
      }
    }
    return primes;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class SieveV2 {

  public static List<Integer> allPrimes(int max) {
    List<Integer> primes = new ArrayList<>();
    for (int n = 2; n <= max; n++) {
      boolean isPrime = true;
      for (Integer prime : primes) {
        if (n % prime == 0) {
          isPrime = false;
          break; // l'ajout du 'break' permet de sortir du 'for' et sauter ligne 18.
        }
      }
      if (isPrime) {
        primes.add(n);
      }
    }
    return primes;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class SieveV3 {

  public static List<Integer> allPrimes(int max) {
    List<Integer> primes = new ArrayList<>();
    for (int n = 2; n <= max; n++) {
      // On extrait en une méthode le test de primalité de 'n', on appelle la
      // nouvelle méthode directement dans la condition du 'if'
      if (isPrime(primes, n)) {
        primes.add(n);
      }
    }
    return primes;
  }

  private static boolean isPrime(List<Integer> primes, int n) {
    boolean isPrime = true;
    for (Integer prime : primes) {
      if (n % prime == 0) {
        isPrime = false;
        break;
      }
    }
    return isPrime;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class SieveV4 {

  public static List<Integer> allPrimes(int max) {
    List<Integer> primes = new ArrayList<>();
    for (int n = 2; n <= max; n++) {
      if (isPrime(primes, n)) {
        primes.add(n);
      }
    }
    return primes;
  }

  // On utilise l'early-exit, en faisant un 'return' dès que la solution
  // est connue, ce qui permet de supprimer la variable 'isPrime'.
  // Le 'break' devient un 'return'
  private static boolean isPrime(List<Integer> primes, int n) {
    for (Integer prime : primes) {
      if (n % prime == 0) {
        return false;
      }
    }
    return true;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.ArrayList;
import java.util.List;

public class SieveV5 {

  public static List<Integer> allPrimes(int max) {
    List<Integer> primes = new ArrayList<>();
    for (int n = 2; n <= max; n++) {
      if (isPrime(primes, n)) {
        primes.add(n);
      }
    }
    return primes;
  }

  // En extrayant le test du 'if' dans sa propre méthode, on donne un
  // nom à la méthode, qui clarifie le rôle du test. C'est un petit
  // changement, mais la méthode en devient plus lisible.
  private static boolean isPrime(List<Integer> primes, int n) {
    for (Integer prime : primes) {
      if (divides(n, prime)) {
        return false;
      }
    }
    return true;
  }

  private static boolean divides(int n, int prime) {
    return n % prime == 0;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours1;

import java.util.List;

public interface Tree {
  int getValue();
  List<Tree> getChildren();


  static Tree getSampleTree() {
    return node(8,
      node(12,
        node(5),
        node(16,
          node(7),
          node(17))),
      node(10,
        node(19),
        node(2,
          node(11),
          node(13))));
  }



  static Tree node(int content, Tree... children) {
    return new Tree() {
      @Override
      public int getValue() {
        return content;
      }

      @Override
      public List<Tree> getChildren() {
        return List.of(children);
      }
    };
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import fr.univamu.progav.cours.cours1.Tree;

import java.util.ArrayDeque;
import java.util.Deque;


public class BreadthFirstSearchV5 {

  // Une version du parcours en large en utilisant une file, et un élément
  // spécial pour marquer la fin d'un niveau.

  private static final Tree END_OF_LEVEL = Tree.node(0);

  public BreadthFirstSearchV5(Tree root) {
    Deque<Tree> waitingList = new ArrayDeque<>();
    waitingList.offerLast(root);
    waitingList.offerLast(END_OF_LEVEL);
    while (true) {
      Tree currentTree = waitingList.pollFirst();
      if (waitingList.isEmpty()) break;
      if (currentTree == END_OF_LEVEL) {
        System.out.println();
        waitingList.offerLast(END_OF_LEVEL);
        continue;
      }
      System.out.print(currentTree.getValue() + " ");
      enqueueChildren(currentTree, waitingList);
    }
  }

  private static void enqueueChildren(Tree next, Deque<Tree> waitingList) {
    for (Tree child : next.getChildren()) {
      waitingList.offerLast(child);
    }
  }

  public static void main(String[] args) {
    Tree t = Tree.getSampleTree();
    new BreadthFirstSearchV5(t);
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.List;

public class DictionaryWithList {

  // On souhaite compter le nombre de mots distincts d'un roman. Il faut
  // stocker tous les mots vus au moins une fois. Voici une solution
  // à base de liste. Il faut s'assurer qu'un mot n'est pas ajouté deux fois
  // dans la liste.

  private final List<String> words = new ArrayList<>();
  private int count = 0;

  public void fillWith(Scanner scanner) {
    while (scanner.hasNext()) {
      count++;
      String word = scanner.next();
      if (words.contains(word)) continue;
      words.add(word);
      }
  }

  public String findLongestWord() {
    String longest = "";
    for (String word : words) {
      if (word.length() > longest.length()) {
        longest = word;
      }
    }
    return longest;
  }

  public static void main(String[] args) throws FileNotFoundException {
    Scanner scanner = new Scanner(new File("src/main/resources/cyrano.txt"));
    DictionaryWithList dict = new DictionaryWithList();
    long start = System.nanoTime();
    dict.fillWith(scanner);
    long stop = System.nanoTime();
    System.out.println("Nombre de mots distincts : " + dict.words.size());
    System.out.println("Nombre de mots total : " + dict.count);
    System.out.println("Calculé en " + ((stop - start) / 1000000) + "ms.");
  }


  // Problème :
  // c'est lent !
  // Solution :
  // 'List' n'est pas optimisé pour que 'contains' soit rapide. Pour cela,
  // il faut utiliser 'Set'

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Map;

public class DictionaryWithMap {

  // L'utilisation d'une 'Map' permet de mémoriser pour chaque mot, son
  // nombre occurrence. Ici les clés (uniques) sont de type 'String',
  // les valeurs associées sont de type 'Integer'.

  private final Map<String, Integer> words = new HashMap<>();
  private int count = 0;

  // On en profite pour améliorer la solution, pour ne compter que les
  // vrais mots. Un vrai mot est constitué de lettres et possiblement
  // du symbole '-'. On donne une expression régulière : '\\p{IsAlphabetic}'
  // représente toutes les lettres. '[-\\p{IsAlphabetic]' signifie une
  // occurrence de '-' ou d'une lettre. L'étoile dénote la multiplicité.
  // (cf cours d'automates et langages formels)

  public void fillWith(Scanner scanner) {
    while (scanner.hasNext()) {
      count++;
      String word = scanner.next();
      if (!word.matches("[-\\p{IsAlphabetic}]*")) continue;
      int occurences = words.getOrDefault(word, 0);
      words.put(word, occurences + 1);
    }
  }

  // On peut boucler sur toutes les entrées clé-valeur d'une Map.

  public Map.Entry<String,Integer> findMostFrequentWord() {
    Map.Entry<String,Integer> best = null;
    for (Map.Entry<String,Integer> entry : words.entrySet()) {
      if (best == null || entry.getValue() > best.getValue()) {
        best = entry;
      }
    }
    return best;
  }

  // On peut boucler uniquement sur les clés avec 'map.keySet()',
  // ou uniquement sur les valeurs avec 'map.getValues()'.

  public String findLongestWord() {
    String longest = "";
    for (String word : words.keySet()) {
      if (word.length() > longest.length()) {
        longest = word;
      }
    }
    return longest;
  }

  public static void main(String[] args) throws FileNotFoundException {
    Scanner scanner = new Scanner(new File("src/main/resources/cyrano.txt"));
    DictionaryWithMap dict = new DictionaryWithMap();
    long start = System.nanoTime();
    dict.fillWith(scanner);
    long stop = System.nanoTime();
    System.out.println("Nombre de mots distincts : " + dict.words.size());
    System.out.println("Nombre de mots total : " + dict.count);
    System.out.println("Calculé en " + ((stop - start) / 1000000) + "ms.");
    System.out.println("Mot le plus long : " + dict.findLongestWord());
    Map.Entry<String,Integer> mostFrequentWord = dict.findMostFrequentWord();
    System.out.println(
      "Mot le plus fréquemment utilisé : " + mostFrequentWord.getKey()
        + " (" + mostFrequentWord.getValue() + ")");
  }


}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class DictionaryWithSet {

  private final Set<String> words = new HashSet<>();
  private int count = 0;

  // En utilisant 'Set', l'unicité est garantie, il n'y a plus besoin
  // de tester si le mot est déjà présent. 'contains' serait néanmoins
  // beaucoup plus efficace qu'avec une liste.

  public void fillWith(Scanner scanner) {
    while (scanner.hasNext()) {
      count++;
      words.add(scanner.next());
    }
  }

  public String findLongestWord() {
    String longest = "";
    for (String word : words) {
      if (word.length() > longest.length()) {
        longest = word;
      }
    }
    return longest;
  }

  public static void main(String[] args) throws FileNotFoundException {
    Scanner scanner = new Scanner(new File("src/main/resources/cyrano.txt"));
    DictionaryWithSet dict = new DictionaryWithSet();
    long start = System.nanoTime();
    dict.fillWith(scanner);
    long stop = System.nanoTime();
    System.out.println("Nombre de mots distincts : " + dict.words.size());
    System.out.println("Nombre de mots total : " + dict.count);
    System.out.println("Calculé en " + ((stop - start) / 1000000) + "ms.");
  }

  // Conclusion :
  // pour stocker des données uniques, avec des opérations
  // d'insertion/suppression/test d'appartenance rapides, 'Set' est
  // le bon choix.
  // Si on veut compter le nombre d'occurences de chaque mot,
  // on utilise 'Map', qui permet en plus de 'Set' d'associer une valeur
  // à chaque élément.

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import java.util.Iterator;

// 'Interval' représente une séquence d'entiers consécutifs. On doit pouvoir
// faire une boucle 'for' sur ces entiers. 'Interval' implémente donc 'Iterable'.

public class Interval implements Iterable<Integer> {
  public final int start;
  public final int stop;

  public Interval(int start, int stop) {
    this.start = start;
    this.stop = stop;
  }

  public static final Interval EMPTY = new Interval(0,-1);

  public Iterator<Integer> iterator() {
    return new Range(start,stop);
  }

  public boolean isEmpty() {
    return start < stop;
  }

  public Interval union(Interval interval) {
    if (interval.isEmpty()) return this;
    if (this.isEmpty()) return interval;
    return new Interval(
      Math.min(this.start, interval.start),
      Math.max(this.stop, interval.stop)
    );
  }

  public static void main(String[] args) {
    int sum = 0;
    for (int next : new Interval(1,10)) {
      sum = sum + next;
      System.out.println(sum);
    }
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import java.util.Iterator;
import java.util.NoSuchElementException;

// 'Range' est un itérateur sur des entiers consécutifs. Il fournit les entiers
// un par un, à chaque appel de 'next'. C'est donc un 'Iterator'.

public class Range implements Iterator<Integer> {
  private int next;
  private final int max;

  public Range(int min, int max) {
    this.next = min;
    this.max = max;
  }

  public boolean hasNext() {
    return next <= max;
  }

  public Integer next() {
    if (!hasNext()) throw new NoSuchElementException();
    return next++;
  }


  public static void main(String[] args) {
    Iterator<Integer> range = new Range(1,10);
    int sum = 0;
    while (range.hasNext()) {
      int next = range.next();
      sum = sum + next;
      System.out.println(sum);
    }
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;

import java.util.Iterator;
import java.util.function.DoubleUnaryOperator;

// 'Sequence' est une suite de nombres définis récursivement par une
// équation de la forme $u_{n+1} = f(u_n)$, $u_0 = c$. On doit
// pouvoir faire une boucle 'for' (infinie) sur les termes.
// 'Sequence' est donc 'Iterable'.

public class Sequence implements Iterable<Double> {
  private final DoubleUnaryOperator f;
  private final double initialValue;

  public Sequence(DoubleUnaryOperator f, double x0) {
    this.f = f; this.initialValue = x0;
  }

  public double term(int i) {
    for (Double d : this) {
      if (i == 0) return d;
      i--;
    }
    return 0;
  }

  public Iterator<Double> iterator() {
    return new SequenceIterator(f,initialValue);
  }

  public static void main(String[] args) {
    Sequence seq = new Sequence(x -> 2 * x + 1, 1);
    for (int i = 0; i < 10; i++) {
      System.out.println(seq.term(i));
    }
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours3;


import java.util.Iterator;
import java.util.function.DoubleUnaryOperator;


// 'SequenceIterator' fournit les termes d'une suite mathématique un par
// un, à chaque appel de 'next'. C'est un 'Iterator'.

public class SequenceIterator implements Iterator<Double> {
  private final DoubleUnaryOperator f;
  private double nextValue;

  public SequenceIterator(DoubleUnaryOperator f, double x0) {
    this.f = f;
    this.nextValue = x0;
  }

  public boolean hasNext() { return true; }

  public Double next() {
    double current = nextValue;
    nextValue = f.applyAsDouble(nextValue);
    return current;
  }



  public static void main(String[] args) {
    double target = 10;
    double epsilon = 1e-6;
    Sequence newtonRoot = new Sequence(x -> 0.5 * (x + target / x), target);
    for (Double possibleRoot : newtonRoot) {
      System.out.println(possibleRoot);
      if (Math.abs(Math.pow(possibleRoot, 2) - target) < epsilon) {
        break;
      }
    }
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours4;

public enum Month {
  JANUARY(31),
  FEBRUARY(28),
  MARCH(31),
  APRIL(30),
  MAY(31),
  JUNE(30),
  JULY(31),
  AUGUST(31),
  SEPTEMBER(30),
  OCTOBER(31),
  NOVEMBER(30),
  DECEMBER(31);

  public final int nbDays;

  private Month(int nbDays) {
    this.nbDays = nbDays;
  }

  public int getNbDays() {
    return switch(this) {
      case JANUARY, MARCH, MAY, JULY, AUGUST, OCTOBER, DECEMBER -> 31;
      case FEBRUARY -> 28;
      case APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30;
    };
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours4;

public class Point2D {
  record Vector2D(double x, double y) {

    // propriétés statiques
    public static final Vector2D NULL = new Vector2D(0,0);
    public static final Vector2D[] roots6 = new Vector2D[6];

    // initialiseur statique
    static {
      for (int i = 0; i < 6; i++) {
        roots6[i] = polar(1, i * Math.PI / 6);
      }
    }

    // méthode statique
    public static Vector2D polar(double norm,
      double angle) {
      return new Vector2D(norm * Math.cos(angle),norm * Math.sin(angle));
    }

    // méthode d'objet
    public Vector2D add(Vector2D addend) {
      return new Vector2D(this.x + addend.x,this.y + addend.y);
    }
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours4;

public record Rational(int denom, int num) {

  // constructeur redéfinit
  public Rational(int denom, int num) {
    // Validité des valeurs :
    if (num == 0) { throw new ArithmeticException(); }
    // Normalisation :
    int g = gcd(Math.abs(denom), Math.abs(num));
    int sign = ((num >= 0) == (denom > 0)) ? 1 : -1;
    this.denom = sign * Math.abs(denom) / g;
    this.num = Math.abs(num) /g;
  }


  private static int gcd(int a, int b) {
    while (b > 0) {
      int remain = a % b;
      a = b;  b = remain;
    }
    return a;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours4;

public enum Suit {
  SPADES ("spades", '♠'),
  HEARTS ("hearts", '♡'),
  DIAMONDS ("diamonds", '♢'),
  CLUBS ("clubs", '♣');

  private final String name ;
  private final char symbol;

  private Suit(String name, char symbol) {
    this.name = name;
    this.symbol = symbol;
  }

  @Override
  public String toString() {
    return name;
  }

  public char getSymbol() {
    return symbol;
  }

  public boolean isRed() {
    switch (this) {
      case Suit.HEARTS :
      case Suit.DIAMONDS : return true;
      default : return false;
    }
  }

  public boolean isBlack() {
    return switch (this) {
      case Suit.HEARTS, Suit.DIAMONDS -> false;
      case Suit.SPADES, Suit.CLUBS -> true;
    };
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours4.TrainTicket;

import java.time.LocalDateTime;

public record BookingTicket(
      Station departure,
      Station destination,
      String seat,
      LocalDateTime departureTime,
      LocalDateTime arrivalTime) implements TrainTicket {
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours4.TrainTicket;

public sealed interface TrainTicket
  permits StandardTicket, BookingTicket, UnlimitedTicket
{


  // switch instructionnel
  static boolean isDeparture(TrainTicket ticket, Station station) {
    switch (ticket) {
      case StandardTicket stdTicket :
        return stdTicket.departure().equals(station);
      case BookingTicket bkgTicket :
        return bkgTicket.departure().equals(station);
      case UnlimitedTicket ultdTicket :
        return true; // any station is a possible departure
    }
  }

  // switch expressionnel
  static boolean isDestination(TrainTicket ticket, Station station) {
    return switch (ticket) {
      case StandardTicket stdTicket -> stdTicket.destination().equals(station);
      case BookingTicket bkgTicket -> bkgTicket.destination().equals(station);
      case UnlimitedTicket _ -> true;
    };
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.InductiveList;

import java.util.Iterator;


public abstract sealed class AbstractLinkedList<E> implements LinkedList<E>
  permits EmptyLinkedList, NonEmptyLinkedList {

  public abstract boolean isEmpty();
  public abstract E head();
  public abstract AbstractLinkedList<E> tail();
  public abstract int length();

  public AbstractLinkedList<E> add(E elt) {
    return new NonEmptyLinkedList<>(elt,this);
  }
  public Iterator<E> iterator() {
    return new ListIterator<E>(this);
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.InductiveList;

import java.security.InvalidParameterException;

public final class EmptyLinkedList<E> extends AbstractLinkedList<E> {
  @Override
  public boolean isEmpty() {
    return true;
  }

  @Override
  public E head() {
    throw new InvalidParameterException("head of empty list");
  }

  @Override
  public AbstractLinkedList<E> tail() {
    throw new InvalidParameterException("tail of empty list");
  }

  @Override
  public int length() {
    return 0;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.InductiveList;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class ListIterator<E> implements Iterator<E> {

  private AbstractLinkedList<E> list;

  public ListIterator(AbstractLinkedList<E> list) {
    this.list = list;
  }

  @Override
  public boolean hasNext() {
    return !list.isEmpty();
  }

  @Override
  public E next() {
    if (!this.hasNext()) {
      throw new NoSuchElementException();
    }
    E next = list.head();
    list = list.tail();
    return next;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.InductiveList;

public class Main {

  public static void main(String[] args) {
    LinkedList<Integer> list0 = new EmptyLinkedList<>();
    LinkedList<Integer> list1 = list0.add(1);
    LinkedList<Integer> list2 = list1.add(3);
    LinkedList<Integer> list3 = list2.add(2);
    for (int elt : list3) {
      System.out.println(elt);
    }
    System.out.println();
    for (int elt : list1) {
      System.out.println(elt);
    }
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.InductiveList;

public final class NonEmptyLinkedList<E> extends AbstractLinkedList<E> {
  private final E head;
  private final AbstractLinkedList<E> tail;

  public NonEmptyLinkedList(E head, AbstractLinkedList<E> tail) {
    this.head = head;
    this.tail = tail;
  }

  @Override
  public boolean isEmpty() {
    return false;
  }

  @Override
  public E head() {
    return this.head;
  }

  @Override
  public AbstractLinkedList<E> tail() {
    return this.tail;
  }

  @Override
  public int length() {
    return 1 + tail.length();
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

// on rend la classe abstraite
public abstract class AbstractReduceListV4 {
  private final List<Integer> ints;

  public AbstractReduceListV4(List<Integer> ints) {
    this.ints = ints;
  }

  public int eval() {
    int sum = neutral();
    for (Integer i : ints) {
      sum = operator(sum, i);
    }
    return sum;
  }

  // on abstrait les méthodes représentant les comportements distincts.

  public abstract int neutral();

  public abstract int operator(int a, int b);
}

Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

public class ProductListV1 {
  private final List<Integer> ints;

  public ProductListV1(List<Integer> ints) {
    this.ints = ints;
  }

  public int eval() {
    int product = 1;
    for (Integer i : ints) {
      product = product * i;
    }
    return product;
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

public class ProductListV2 {
  private final List<Integer> ints;

  public ProductListV2(List<Integer> ints) {
    this.ints = ints;
  }

  // on extrait les comportements distincts des comportements communs

  public int eval() {
    int product = neutral();
    for (Integer i : ints) {
      product = operator(product, i);
    }
    return product;
  }

  // chaque comportement distinct est déporté dans une méthode

  private  int operator(int a, int b) {
    return a * b;
  }

  private int neutral() {
    return 1;
  }


}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

// On déclare une extension de la classe abstraite des comportements communs
public class ProductListV4 extends AbstractReduceListV4 {
  public ProductListV4(List<Integer> ints) {
    super(ints);
  }

  // On spécialise les comportements distincts selon la fonctionnalité voulue.

  @Override
  public int neutral() {
    return 1;
  }

  @Override
  public int operator(int a, int b) {
    return a * b;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

public class ReduceListV3 {

  // On crée une interface regroupant les comportements distincts
  // (on peut la mettre dans son propre fichier)
  public interface IntMonoid {
    int neutral();
    int operator(int a, int b);
  }

  private final List<Integer> ints;
  // on ajoute un objet pour les comportements distincts
  private final IntMonoid monoid;



  // on initialise l'objet que recevra la délégation, par exemple dans le constructeur
  public ReduceListV3(List<Integer> ints, IntMonoid monoid) {
    this.ints = ints;
    this.monoid = monoid;
  }

  // on délègue les comportements distincts au nouvel objet
  public int eval() {
    int sum = monoid.neutral();
    for (Integer i : ints) {
      sum = monoid.operator(sum, i);
    }
    return sum;
  }

  // On peut ajouter des fabriquants statiques pour revenir sur
  // les fonctionnalités initiales

  static class SumMonoid implements ReduceListV3.IntMonoid {
    public int neutral() { return 0; }
    public int operator(int a, int b) { return a + b; }
  }

  public static ReduceListV3 sumList(List<Integer> ints) {
    return new ReduceListV3(ints, new SumMonoid());
  }

  static class ProductMonoid implements IntMonoid {
    public int neutral() { return 1; }
    public int operator(int a, int b) { return a * b; }
  }

  public static ReduceListV3 productList(List<Integer> ints) {
    return new ReduceListV3(ints, new ProductMonoid());
  }
}

Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

public class SumListV1 {
  private final List<Integer> ints;

  public SumListV1(List<Integer> ints) {
    this.ints = ints;
  }

  public int eval() {
    int sum = 0;
    for (Integer i : ints) {
      sum = sum + i;
    }
    return sum;
  }
}

Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

public class SumListV2 {
  private final List<Integer> ints;

  // on extrait les comportements distincts des comportements communs

  public SumListV2(List<Integer> ints) {
    this.ints = ints;
  }

  public int eval() {
    int sum = neutral();
    for (Integer i : ints) {
      sum = operator(sum, i);
    }
    return sum;
  }

  // chaque comportement distinct est déporté dans une méthode

  public int neutral() {
    return 0;
  }

  public int operator(int a, int b) {
    return a + b;
  }
}

Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.abstractclasses;

import java.util.List;

// On déclare une extension de la classe abstraite des comportements communs
public class SumListV4 extends AbstractReduceListV4 {
  public SumListV4(List<Integer> ints) {
    super(ints);
  }

  // On spécialise les comportements distincts selon la fonctionnalité voulue.

  @Override
  public int neutral() {
    return 0;
  }

  @Override
  public int operator(int a, int b) {
    return a + b;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.recyclableV1;

import java.util.HashSet;
import java.util.Set;

public class RecycleBin {
  private Set<Object> trash = new HashSet<>() ;

  public void add(Object obj) {
     trash.add(obj);
  }

  public void empty() {
    for (Object obj : trash) {
      if (obj instanceof Can can) can.recycle();
      if (obj instanceof GlassBottle bottle) bottle.recycle();
      if (obj instanceof CardBoard board) board.recycle();
      if (obj instanceof Paper paper) paper.recycle();
    }
  }

  // Problème :
  // pas de type adapté pour les déchets recyclables
  // Ici on utilise le type Object.
  // Si on le change par 'Cardboard', on ne pourra pas jeter des 'GlassBottle'
  // et inversement.
  // Dans cette solution, on peut jeter n'importe quel déchet,
  // même non recyclable.
  // Le type Object ne convient pas car il n'a pas de méthode de recyclage.
  // On est obligé de tester des instanciations : compliqué, et oblige
  // à changer la méthode empty() si on ajoute une nouvelle classe recyclable.
  // Solution :
  // Créer un type commun pour tous les déchets recyclables -> interface
  // Lui attribuer la méthode 'recycle'
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.recyclableV2;

public record Paper(double width, double height) implements Recyclable {

  public void recycle() {
    System.out.println("make some cardboard.");
  }

  public void tear() {
    System.out.println("Tear some paper");
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours5.recyclableV2;

import java.util.*;

public class RecycleBin {
  private Set<Recyclable> trash = new HashSet<>() ;

  public void add(Recyclable obj) {
     trash.add(obj);
  }

  public void empty() {
    for (Recyclable obj : trash) {
       obj.recycle();
    }
  }


  public static void main(String[] args) {
    // On vérifie le bon comportement de la solution
    Paper item1 = new Paper(21,29.7); // OK
    Recyclable item2 = new Paper(10,8); // OK
//    Paper item3 = item2; // Non, l'information "item2 contient du papier" est perdue.
//    Recyclable item4 = new Recyclable(); // Non, Recyclable est une interface donc n'est pas instanciable
//    Paper item5 = new Can(); // Non, une canette n'est pas du papier
    RecycleBin trash = new RecycleBin();
    trash.add(item1); // OK
    trash.add(item2); // OK
    trash.add(new Paper(5,5)); // OK
    trash.add(new Can(0.33)); // OK
    trash.empty();

    // Interaction avec les collections
    List<Recyclable> recyclables = new ArrayList<>();
    recyclables.add(item1); // OK
    recyclables.add(item2); // OK
    List<Paper> papers = new ArrayList<>();
    papers.add(item1); // OK
    // papers.add(item2); // Non, l'information "item2 contient du papier" est perdue.


    // list = papers; // Non, une liste de papiers n'est pas une liste de recyclables
    // papers = list; // Non, une liste de recyclables n'est pas une liste de papiers
  }

  // Règle de typage :
  // c'est le type d'une variable, et non son contenu, qui détermine COMMENT
  // la variable peut être utilisée
  // c'est le contenu, et non le type de la variable, qui détermine l'EFFET
  // de l'utilisation de la variable.
  // (les types existent à la compilation, mais pas à l'exécution du progamme)

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class IntStack implements Iterable<Integer> {
  Integer[] values = new Integer[1000];
  Integer firstEmptyCell = 0;

  boolean isEmpty() {
    return firstEmptyCell == 0;
  }

  public void push(Integer value) {
    values[firstEmptyCell++] = value;
  }

  public Integer peek() {
    if (isEmpty()) {
      throw new NoSuchElementException();
    }
    return values[firstEmptyCell - 1];
  }

  public Integer poll() {
    if (isEmpty()) {
      throw new NoSuchElementException();
    }
    return values[--firstEmptyCell];
  }

  public Iterator<Integer> iterator() {
    return new IntStackIterator(values, firstEmptyCell-1);
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class IntStackIterator implements Iterator<Integer> {

  private final Integer[] values;
  private int current = 0;
  private final int last;

  public IntStackIterator(Integer[] values, int last) {
    this.values = values;
    this.last = last;
  }


  public boolean hasNext() {
    return current <= last;
  }

  public Integer next() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    return values[current++];
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

import java.security.InvalidParameterException;
import java.util.List;

public class Maximum {
  
  // On souhaite calculer le maximum d'une liste. 
  // Le type des éléments est quelconque, on effectue la comparaison 
  // avec la méthode compareTo
  
  public static String maximumString(List<String> elements) {
    if (elements.isEmpty()) {
      throw new InvalidParameterException("maximum of empty list");
    }
    String max = elements.getFirst();
    for (String element : elements) {
      if (element.compareTo(max) > 0) {
        max = element;
      }
    }
    return max;
  }
  
  // Il faut donc introduire un type générique 'T',
  // et remplacer 'String' par 'T' partout.
  // Problème :
  // 'compareTo' n'est pas une méthode possédée par tout type 'T'
  // Solution :
  // ajouter une restriction d'interface au type générique 'T' avec 'extends'

  public static <T extends Comparable<T>> T maximum(List<T> elements) {
    if (elements.isEmpty()) {
      throw new InvalidParameterException("maximum of empty list");
    }
    T max = elements.getFirst();
    for (T element : elements) {
      if (element.compareTo(max) > 0) {
        max = element;
      }
    }
    return max;
  }


  public static void main(String[] args) {
    List<String> words = List.of("foo", "bar", "baz");
    List<Integer> ints = List.of(1, 3, 2);
    System.out.println(maximumString(words));
    System.out.println(maximum(ints));
    System.out.println(maximum(words));

  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

public class PrintCollection {


  // Voici deux fonctions presque identiques.

  public static String writeInts(int[] ints) {
    boolean isFirst = true;
    StringBuilder builder = new StringBuilder();
    for (int i : ints) {
      if (isFirst) { isFirst = false; }
      else { builder.append(", "); }
      builder.append(i);
    }
    return builder.toString();
  }


  public static String writeStrings(String[] strings) {
    boolean isFirst = true;
    StringBuilder builder = new StringBuilder();
    for (String str : strings) {
      if (isFirst) { isFirst = false; }
      else { builder.append(", "); }
      builder.append(str);
    }
    return builder.toString();
  }

  // Peut-on les factoriser ?
  // On repère les comportements identiques et distincts, et on
  // fait une interface pour les comportements distincts.

  // Problème :
  // il n'y a pas de comportement distinct ! seuls les types diffèrent

  // Solution : abstraire les types distincts, ici en un type générique T

  public static <T> String write(T[] values) {
    boolean isFirst = true;
    StringBuilder builder = new StringBuilder();
    for (T t : values) {
      if (isFirst) { isFirst = false; }
      else { builder.append(", "); }
      builder.append(t);
    }
    return builder.toString();
  }

  public static void main(String[] args) {
    int[] ints = { 1,2,3 };
    String[] strings = { "foo", "bar", "baz"};
    writeInts(ints);
    writeStrings(strings);
    // write(ints); // Non, car int est un type primitif, T abstrait les types références
    write(strings);
  }

  // Seule solution pour int[] : surcharger en write(int[] values).
  // Peu satisfaisant, c'est une raison d'éviter d'utiliser les tableaux
  // en java, sauf quand les performances l'exigent.

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

import java.util.List;

// On améliore la solution du cours 5, en abstrayant non seulement le monoïde
// par une interface, mais aussi le type par généricité. Les deux techniques
// se combinent très bien.

public class ReduceList<T> {

  private final List<T> elements;
  private final Monoid<T> monoid;


  public ReduceList(List<T> elements, Monoid<T> monoid) {
    this.elements = elements;
    this.monoid = monoid;
  }

  public T reduce() {
    T result = monoid.neutral();
    for (T element : elements) {
      result = monoid.operator(result, element);
    }
    return result;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

import java.util.Iterator;
import java.util.NoSuchElementException;


@SuppressWarnings("unchecked") // autorise le cast ci-dessous.
public class Stack<T> implements Iterable<Integer> {
  T[] values = (T[]) new Object[1000]; // Cast obligatoire, incompatibilité entre générique et tableau
  Integer firstEmptyCell = 0;

  boolean isEmpty() {
    return firstEmptyCell == 0;
  }

  public void push(T value) {
    values[firstEmptyCell++] = value;
  }

  public T peek() {
    if (isEmpty()) {
      throw new NoSuchElementException();
    }
    return values[firstEmptyCell - 1];
  }

  public T poll() {
    if (isEmpty()) {
      throw new NoSuchElementException();
    }
    return values[--firstEmptyCell];
  }

  public Iterator<Integer> iterator() {
    return new StackIterator(values, firstEmptyCell-1);
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours6;

import java.util.Iterator;
import java.util.NoSuchElementException;

public class StackIterator<T> implements Iterator<T> {

  private final T[] values;
  private int current = 0;
  private final int last;

  public StackIterator(T[] values, int last) {
    this.values = values;
    this.last = last;
  }


  public boolean hasNext() {
    return current <= last;
  }

  public T next() {
    if (!hasNext()) {
      throw new NoSuchElementException();
    }
    return values[current++];
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours7;

import java.util.ArrayList;
import java.util.List;

public class CatalogV1 {

  private final List<Car> cars = new ArrayList<>();

  public CatalogV1() {
    cars.add(new Car("Vaillante", "1985", 18000));
    cars.add(new Car("Vaillante", "1983", 14500));
    cars.add(new Car("Anvil Motors", "2015", 24800));
  }


  public static void main(String[] args) {
    CatalogV1 catalog = new CatalogV1();
    for (Car car : catalog.selectByBrand("Vaillante")) {
      System.out.println(car);
    }
  }

  public List<Car> selectByMaxPrice(int maxPrice) {
    List<Car> selection = new ArrayList<>();
    for (Car car : cars) {
      if (car.price() <= maxPrice) {
        selection.add(car);
      }
    }
    return selection;
  }

  public List<Car> selectByBrand(String brandName) {
    List<Car> selection = new ArrayList<>();
    for (Car car : cars) {
      if (car.brand().equals(brandName)) {
        selection.add(car);
      }
    }
    return selection;
  }

  // Problèmes :
  // - répétitions entre les deux méthodes
  // - que faire si on veut sélectionner les voitures d'une marque et
  // d'un prix limité simultanément ?

  // Solution partielle :
  // factoriser les comportements communs, et utiliser une interface pour
  // les comportements distincts, comme nous savons le faire.
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours7;

import java.util.ArrayList;
import java.util.List;

public class CatalogV2 {

  private final List<Car> cars = new ArrayList<>();

  public CatalogV2() {
    cars.add(new Car("Vaillante", "1985", 18000));
    cars.add(new Car("Vaillante", "1983", 14500));
    cars.add(new Car("Anvil Motors", "2015", 24800));
  }


  public static void main(String[] args) {
    CatalogV2 catalog = new CatalogV2();
    for (Car car : catalog.selectByBrand("Vaillante")) {
      System.out.println(car);
    }
  }

  // on introduit l'interface pour les comportements distincts
  public interface CarPredicate {
    boolean isValid(Car car);
  }

  // on délègue à l'interface les comportements distincts
  public List<Car> selectByCriterion(CarPredicate predicate) {
    List<Car> selection = new ArrayList<>();
    for (Car car : cars) {
      if (predicate.isValid(car)) {
        selection.add(car);
      }
    }
    return selection;
  }

  // on spécialise en définissant des objets à qui déléguer
  private static class MaxPriceCriterion implements CarPredicate {
    private final double maxPrice;

    MaxPriceCriterion(double maxPrice) {
      this.maxPrice = maxPrice;
    }

    @Override
    public boolean isValid(Car car) {
      return car.price() <= maxPrice;
    }
  }

  public List<Car> selectByMaxPrice(int maxPrice) {
    return selectByCriterion(new MaxPriceCriterion(maxPrice));
  }

  private static class HasBrand implements CarPredicate {
    private final String brandName;

    public HasBrand(String brandName) {
      this.brandName = brandName;
    }

    @Override
    public boolean isValid(Car car) {
      return brandName.equals(car.brand());
    }
  }


  public List<Car> selectByBrand(String brandName) {
    return selectByCriterion(new HasBrand(brandName));
  }


  // On a factorisé les comportements distincts, mais :
  // Problèmes :
  // - c'est plus verbeux et long que la solution initiale
  // - que faire si on veut sélectionner les voitures d'une marque et
  // d'un prix limité simultanément ?

  // Solution partielle :
  // utiliser une syntaxe abrégée pour créer les objets prédicats.
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours7;

import java.util.ArrayList;
import java.util.List;

public class CatalogV3 {

  private final List<Car> cars = new ArrayList<>();

  public CatalogV3() {
    cars.add(new Car("Vaillante", "1985", 18000));
    cars.add(new Car("Vaillante", "1983", 14500));
    cars.add(new Car("Anvil Motors", "2015", 24800));
  }


  public static void main(String[] args) {
    CatalogV3 catalog = new CatalogV3();
    for (Car car : catalog.selectByBrand("Vaillante")) {
      System.out.println(car);
    }
  }


  public interface CarPredicate {
    boolean isValid(Car car);
  }

  public List<Car> selectByCriterion(CarPredicate predicate) {
    List<Car> selection = new ArrayList<>();
    for (Car car : cars) {
      if (predicate.isValid(car)) {
        selection.add(car);
      }
    }
    return selection;
  }



  public List<Car> selectByMaxPrice(int maxPrice) {
    return selectByCriterion(new CarPredicate() {
      @Override
      public boolean isValid(Car car) {
        return car.price() <= maxPrice;
      }
    });
  }



  public List<Car> selectByBrand(String brandName) {
    return selectByCriterion(new CarPredicate() {
      @Override
      public boolean isValid(Car car) {
        return brandName.equals(car.brand());
      }
    });
  }



  // L'utilisation de classes anonymes réduit la verbosité
  // Problèmes :
  // - cela reste un peu long, et très peu lisible.
  // - que faire si on veut sélectionner les voitures d'une marque et
  // d'un prix limité simultanément ?

  // Solution partielle :
  // utiliser une syntaxe encore plus abrégée pour créer les objets prédicats.
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours7;

import java.util.ArrayList;
import java.util.List;

public class CatalogV4 {

  private final List<Car> cars = new ArrayList<>();

  public CatalogV4() {
    cars.add(new Car("Vaillante", "1985", 18000));
    cars.add(new Car("Vaillante", "1983", 14500));
    cars.add(new Car("Anvil Motors", "2015", 24800));
  }


  public static void main(String[] args) {
    CatalogV4 catalog = new CatalogV4();
    for (Car car : catalog.selectByBrand("Vaillante")) {
      System.out.println(car);
    }
  }

  // Puisque 'CarPredicate' ne déclare qu'une seule méthode,
  // c'est une interface fonctionnelle, et on peut la déclarer
  // comme telle avec l'annotation '@FunctionalInterface'

  @FunctionalInterface
  public interface CarPredicate {
    boolean isValid(Car car);
  }

  public List<Car> selectByCriterion(CarPredicate predicate) {
    List<Car> selection = new ArrayList<>();
    for (Car car : cars) {
      if (predicate.isValid(car)) {
        selection.add(car);
      }
    }
    return selection;
  }


  // Puisque 'CarPredicate' est une interface fonctionnelle, on peut
  // créer des objets ayant cette interface avec des lambdas
  // (dont la syntaxe est 'arguments -> expression')


  public List<Car> selectByMaxPrice(int maxPrice) {
    return selectByCriterion(car -> car.price() <= maxPrice);
  }


  public List<Car> selectByBrand(String brandName) {
    return selectByCriterion(car -> brandName.equals(car.brand()));
  }



  // L'utilisation des lambdas rend le programme court et lisible
  // Problème restant :
  // - que faire si on veut sélectionner les voitures d'une marque et
  // d'un prix limité simultanément ?

  // Solution partielle :
  // on peut bien sûr faire une lambda adaptée
  // car -> car.price() <= maxPrice && brandName.equals(car.brand())
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours7;

import java.util.ArrayList;
import java.util.List;

public class CatalogV5 {

  private final List<Car> cars = new ArrayList<>();

  public CatalogV5() {
    cars.add(new Car("Vaillante", "1985", 18000));
    cars.add(new Car("Vaillante", "1983", 14500));
    cars.add(new Car("Anvil Motors", "2015", 24800));
  }



  // En utilisant des méthodes par défaut, on peut ajouter des combinateurs
  // permettant de manipuler les prédicats

  @FunctionalInterface
  public interface CarPredicate {
    boolean isValid(Car car);

    default CarPredicate negate() {
      return car -> !this.isValid(car);
    }

    default CarPredicate and(CarPredicate predicate) {
      return car -> this.isValid(car) && predicate.isValid(car);
    }

    default CarPredicate or(CarPredicate predicate) {
      return car -> this.isValid(car) || predicate.isValid(car);
    }
  }

  public List<Car> selectByCriterion(CarPredicate predicate) {
    List<Car> selection = new ArrayList<>();
    for (Car car : cars) {
      if (predicate.isValid(car)) {
        selection.add(car);
      }
    }
    return selection;
  }


  // Ce sera plus pratique d'avoir les prédicats à disposition, pour
  // pouvoir les combiner

  private CarPredicate hasMaxPrice(int maxPrice) {
    return car -> car.price() <= maxPrice;
  }

  private CarPredicate hasBrand(String brand) {
    return car -> brand.equals(car.brand());
  }

  public List<Car> selectByMaxPrice(int maxPrice) {
    return selectByCriterion(hasMaxPrice(maxPrice));
  }


  public List<Car> selectByBrand(String brandName) {
    return selectByCriterion(hasBrand(brandName));
  }

  public List<Car> selectByPriceAndBran(int maxPrice, String brandName) {
    return selectByCriterion(hasMaxPrice(maxPrice).and(hasBrand(brandName)));
  }


  public static void main(String[] args) {
    CatalogV5 catalog = new CatalogV5();
    for (Car car : catalog.selectByCriterion(catalog.hasMaxPrice(15000).and(catalog.hasBrand("Vaillante")))) {
      System.out.println(car);
    }
  }


  // Conclusion :
  // Solution concise et modulable !
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours8;

public record Car(
  String brand,
  String model,
  int topSpeed,
  boolean hasAutomaticTransmission,
  int productionYear,
  int price) {
}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours8;

import java.util.List;
import java.util.NoSuchElementException;

public class CarAnalyzerV1 {
  private static final List<Car> cars = List.of(
    new Car("Vaillante","Vaillante F1", 340, false, 1999, 1250000),
    new Car("Anvil Motors","Elegy RH8", 250, true, 2006, 90000),
    new Car("Vaillante","Vaillante GT", 270, false, 1994, 110000),
    new Car("Vaillante","Junior", 180, true, 2002, 24000),
    new Car("Anvil Motors","Camper", 150, true, 2003, 65000),
    new Car("Vaillante","NEUILLY", 225, true, 2005, 53500)
    );

  private static final int CURRENT_YEAR = 2025;

  public static double averageAgeOfFastAutomaticVaillanteCars(List<Car> cars) {
    int count = 0;
    int sumAge = 0;
    for (Car car : cars) {
      if (!"Vaillante".equals(car.brand())
        || !car.hasAutomaticTransmission()
        || car.topSpeed() < 200) {
        continue;
      }
      sumAge = sumAge + (CURRENT_YEAR - car.productionYear());
      count++;
    }
    if (count == 0) { throw new NoSuchElementException(); }
    return (double) sumAge / count;
  }


  public static void main(String[] args) {
    System.out.println(averageAgeOfFastAutomaticVaillanteCars(cars));
  }
}

// Problème :
// méthode modérément complexe, difficile à lire. Il serait facile de faire une
// petite erreur et de ne pas s'en rendre compte.
// Solution :
// - découper en plusieurs méthodes (une pour le prédicat, une pour construire
// une liste intermédiaire de voitures qui satisfont les critères, une
// calculant la moyenne)
// - ou bien, utiliser une Stream
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours8;

import java.util.List;
import java.util.NoSuchElementException;

public class CarAnalyzerV2 {
  private static final List<Car> cars = List.of(
    new Car("Vaillante","Vaillante F1", 340, false, 1999, 1250000),
    new Car("Anvil Motors","Elegy RH8", 250, true, 2006, 90000),
    new Car("Vaillante","Vaillante GT", 270, false, 1994, 110000),
    new Car("Vaillante","Junior", 180, true, 2002, 24000),
    new Car("Anvil Motors","Camper", 150, true, 2003, 65000),
    new Car("Vaillante","NEUILLY", 225, true, 2005, 53500)
    );

  private static final int CURRENT_YEAR = 2025;



  public static double averageAgeOfFastAutomaticVaillanteCars(List<Car> cars) {
    return cars.stream()
      .filter(car -> "Vaillante".equals(car.brand()))
      .filter(car -> car.hasAutomaticTransmission())
      .filter(car -> car.topSpeed() >= 200)
      .mapToInt(car -> car.productionYear())
      .average()
      .orElseThrow(() -> new NoSuchElementException());
  }


  public static void main(String[] args) {
    System.out.println(averageAgeOfFastAutomaticVaillanteCars(cars));
  }
}


// structure simple (plus de if, de for, de variables à gérer), donc :
// - difficile de faire une erreur
// - plus facile à lire (le code décrit l'intention, et non le calcul)
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours8;

import java.util.List;
import java.util.NoSuchElementException;

public class CarAnalyzerV3 {
  private static final List<Car> cars = List.of(
    new Car("Vaillante","Vaillante F1", 340, false, 1999, 1250000),
    new Car("Anvil Motors","Elegy RH8", 250, true, 2006, 90000),
    new Car("Vaillante","Vaillante GT", 270, false, 1994, 110000),
    new Car("Vaillante","Junior", 180, true, 2002, 24000),
    new Car("Anvil Motors","Camper", 150, true, 2003, 65000),
    new Car("Vaillante","NEUILLY", 225, true, 2005, 53500)
    );

  private static final int CURRENT_YEAR = 2025;



  public static double averageAgeOfFastAutomaticVaillanteCars(List<Car> cars) {
    return cars.stream()
      .filter(car -> "Vaillante".equals(car.brand()))
      .filter(Car::hasAutomaticTransmission)
      .filter(car -> car.topSpeed() >= 200)
      .mapToInt(Car::productionYear)
      .average()
      .orElseThrow(NoSuchElementException::new);
  }


  public static void main(String[] args) {
    System.out.println(averageAgeOfFastAutomaticVaillanteCars(cars));
  }
}
// structure simple (plus de if, de for, de variables à gérer), donc :
// - difficile de faire une erreur
// - plus facile à lire (le code décrit l'intention, et non le calcul)
 No newline at end of file
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours9;

import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;

public class IntListReader {

  public static List<Integer> readV1(String file) throws IOException {
    Scanner scanner = new Scanner(Path.of(file));
    List<Integer> ints = new ArrayList<>();
    try {
      while (scanner.hasNext()) {
        ints.add(scanner.nextInt());
      }
    } catch (InputMismatchException exc) {
      System.out.println("Wrong input at " + ints.size());
    } finally {
      scanner.close();
    }
    return ints;
  }

  public static List<Integer> readV2(String file) throws IOException {
    List<Integer> ints = new ArrayList<>();
    try (Scanner scanner = new Scanner(Path.of("data.txt"))) {
      while (scanner.hasNext()) {
        ints.add(scanner.nextInt());
      }
    } catch (InputMismatchException exc) {
      System.out.println("Wrong input at " +  ints.size());
    }
    return ints;
  }


  public static void analyzeFile(String filename) {
    List<Integer> valid = null;
    System.out.println("File:" + filename);
    try {
      valid = readV1(filename);
      valid.forEach(System.out::println);
    } catch (IOException e) {
      System.out.println("Unable to open file");
    }
  }

  public static void main(String[] args) {
    analyzeFile("src/main/resources/validInts.txt");
    analyzeFile("src/main/resources/invalidInts.txt");
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours9;

public class MainRoulette {

  // Exemple d'une méthode pouvant propager l'exception

  private static void playThreeTimes(Roulette roulette)
  throws Roulette.ZeroException {
    for (int i = 0; i < 3; i++) {
      System.out.println(
        (roulette.roll() % 2 == 0) ? "Pair" : "Impair"
      );
    }
  }


  // Exemple d'une méthode pouvant rattraper l'exception

  public static void main(String[] args) {
    Roulette roulette = new Roulette();
    try {
      playThreeTimes(roulette);
    }
    catch (Roulette.ZeroException exc) {
      System.out.println("Zéro, la banque prend tout !");
    }
  }

}
Original line number Diff line number Diff line
package fr.univamu.progav.cours.cours9;

import java.util.Random;

public class Roulette {

  private static final Random gen = new Random();

  // Déclaration d'une classe d'exception
  public static class ZeroException extends Exception {}

  // Cette méthode lève l'exception dans certains cas
  public int roll() throws ZeroException {
    int result = gen.nextInt(37);
    if (result == 0) {
      throw new ZeroException();
    }
    return result;
  }
}
Original line number Diff line number Diff line
package fr.univamu.progav.td2;
package fr.univamu.progav.td.td2;

public class Ratio {

@@ -22,7 +22,7 @@ public class Ratio {

  // UnsafeOf is used in test, to build a ratio without reducing it,
  // and must be used with already reduced numerator and denominator.
  protected static Ratio unsafeOf(int num, int denom) {
  public static Ratio unsafeOf(int num, int denom) {
    return new Ratio(num, denom);
  }