HashMap et collections en Java

Apprends à stocker et à rechercher des données par clé avec HashMap, à compter et à regrouper des valeurs, et à conserver des valeurs distinctes avec HashSet. Découvre les garanties des interfaces List, Set et Map, trie des listes, donne un ordre naturel à tes propres classes avec Comparable et choisis la collection adaptée à chaque tâche.

DébutantUnité 7 sur 11 de la formation Formation : Java orienté objet : classes, collections, héritage et tests

Ce que tu vas apprendre

  1. Crée des Map de hachage, ajoute, lis, mets à jour et supprime des paires clé–valeur, parcours le contenu d’une Map et utilise tes propres classes comme clés que la Map peut retrouver.
    • Crée une HashMap, puis ajoute, consulte, mets à jour et supprime des entrées
      Déclare une HashMap avec ses types de clé et de valeur, stocke des paires avec put, lis-les avec get et traite les clés absentes.
    • Parcours les clés, les valeurs et les entrées
      Parcours chaque paire d’une Map avec keySet, values et entrySet, identifie l’ordre possible et modifie une Map sans erreur pendant son parcours.
    • Utilise tes propres objets comme clés de Map
      Rends les objets de tes propres classes utilisables comme clés en redéfinissant equals et hashCode ensemble, et ne modifie pas les clés tant qu’elles sont dans une Map.
  2. Utilise des Map pour compter les occurrences, réunir des valeurs liées sous une même clé et construire des tables de correspondance qui retrouvent rapidement des objets.
    • Compte les occurrences et calcule les sommes par clé
      Construis des tableaux des effectifs et des sommes cumulées avec le schéma getOrDefault, puis lis correctement les résultats.
    • Regroupe des valeurs sous une même clé en utilisant des listes et des ensembles comme valeurs
      Construis des Map dont les valeurs sont des listes ou des ensembles, ajoute les éléments au bon groupe et évite les erreurs qui font perdre ou endommagent des groupes.
    • Recherche rapidement des objets et des prix avec un index fondé sur une Map
      Utilise des Map comme tables de correspondance et index pour trouver des objets par une clé unique, conserve-les dans une classe et maintiens la cohérence entre plusieurs index.
  3. Utilise HashSet pour stocker des valeurs sans doublons, teste rapidement l’appartenance et combine des ensembles par union, intersection et différence.
    • Stocke des valeurs distinctes et teste l’appartenance avec HashSet
      Ajoute, vérifie et supprime des valeurs dans une HashSet, utilise le résultat de add et supprime les doublons d’une liste.
    • Combine des ensembles et préserve leur ordre
      Calcule des unions, des intersections et des différences sans modifier les ensembles d’origine, compare des ensembles et choisis un ensemble ordonné lorsque l’ordre compte.
  4. Déclare les collections avec leurs types interface, identifie les garanties de chaque interface et utilise les méthodes communes aux différentes implémentations.
    • Déclare des variables et des paramètres de type interface
      Explique ce qu’est un type interface, déclare des collections comme List, Set ou Map et écris des méthodes qui acceptent toute implémentation.
    • Identifie les garanties de List, Set et Map
      Compare les garanties des trois interfaces, reconnais leurs principales implémentations et manipule des collections non modifiables créées avec of.
  5. Trie des listes dans l’ordre naturel, donne un ordre naturel à tes propres classes en implémentant Comparable et utilise cet ordre dans des ensembles et des Map triés.
    • Trie des listes de nombres et de chaînes
      Trie une liste en place avec Collections.sort, prévois l’ordre des chaînes et trie dans l’ordre inverse ou sans tenir compte de la casse.
    • Implémente Comparable dans ta propre classe
      Donne un ordre naturel à une classe en implémentant Comparable et en écrivant compareTo avec des comparaisons sûres de nombres et de chaînes.
    • Départage les égalités et utilise des ensembles et des Map triés
      Ordonne des objets selon plusieurs champs, assure la cohérence de compareTo avec equals et utilise TreeSet et TreeMap pour conserver des données triées.
  6. Compare la vitesse des opérations courantes dans chaque collection et choisis le type adapté à ce que le programme doit faire avec ses données.
    • Compare le coût des opérations courantes sur les collections
      Estime comment le temps des recherches, des insertions et des suppressions augmente avec la taille de chaque collection, et repère les schémas lents.
    • Choisis une collection qui répond aux besoins de la tâche
      Réponds à quelques questions sur l’ordre, les doublons et la recherche pour choisir entre tableaux, listes, ensembles et Map, puis combine-les pour des données plus complexes.

HashMap et collections en Java : cours

6 chapitres

1

Stocke et recherche des données par clé avec HashMap

Un code produit peut mener directement à une quantité en stock, sans parcourir une liste. Les Map rendent ce lien explicite, mais pour bien les utiliser, il faut aussi traiter les clés absentes, parcourir les paires sans erreur et définir quand deux objets servant de clés sont considérés comme égaux. Commence par une petite Map de stocks, puis suis les changements de son contenu et la façon dont Java retrouve une clé stockée. Les mêmes règles d’égalité compteront lorsque tu utiliseras des ensembles.

1.1 Crée une HashMap, puis ajoute, consulte, mets à jour et supprime des entrées

Une Map stocke une association entre chaque clé et une valeur. Dans une Map de stocks, un nom de produit est la clé et sa quantité est la valeur. Deux produits peuvent avoir la même quantité, mais une clé de produit ne peut pas correspondre à deux entrées distinctes.

Créer la Map
import java.util.HashMap;

HashMap<String, Integer> stock = new HashMap<>();

Le premier type, String, décrit les clés. Le second, Integer, décrit les valeurs. Le diamant <> à droite permet à Java de déduire ces types. Les arguments de type doivent être des types référence : utilise Integer, Double, Character ou Boolean au lieu de int, double, char ou boolean. Java effectue l’autoboxing d’un simple int lorsqu’il le stocke comme Integer, et l’unboxing d’un Integer lorsqu’un int est nécessaire.

Suivre chaque modification
stock.put("apple", 12);
stock.put("pear", 7);
Integer previous = stock.put("apple", 15);

Le premier appel crée apple=12 ; le deuxième ajoute pear=7. Le troisième trouve la clé "apple" existante et remplace sa valeur. La Map contient maintenant deux entrées et previous contient 12. Un appel à put pour une clé sans association précédente renvoie null.

stock.get("apple") renvoie maintenant 15. stock.remove("pear") renvoie 7 et supprime cette entrée. Une nouvelle suppression de "pear" renvoie null. size() compte les entrées, isEmpty() vérifie s’il n’y en a aucune et clear() les supprime toutes.

Traiter une clé absente

stock.get("kiwi") renvoie null et stock.containsKey("kiwi") renvoie false. Cette instruction se compile mais échoue à l’exécution :

int quantity = stock.get("kiwi");

Java essaie d’effectuer l’unboxing de null en int, ce qui provoque une NullPointerException. Pour une Map de quantités non nulles, utilise une valeur par défaut :

int quantity = stock.getOrDefault("kiwi", 0);

Cela donne 0 sans ajouter "kiwi" à la Map. Tu peux aussi vérifier avec containsKey avant la lecture. containsValue(15) vérifie si une entrée possède cette valeur ; la méthode peut parcourir toutes les valeurs, ce qui diffère de la recherche d’une clé connue.

Une HashMap autorise aussi une clé null et des valeurs null. Si une clé est explicitement associée à null, getOrDefault renvoie ce null stocké, et non la valeur par défaut. containsKey distingue ce cas d’une clé absente. Les Map de quantités sont plus simples lorsque chaque quantité stockée est une valeur numérique plutôt que null.

Faire correspondre correctement les clés et les valeurs

Les clés de type String sont sensibles à la casse : "apple", "Apple" et "apple " sont différentes. Applique le même nettoyage avant le stockage et la recherche, par exemple avec name.trim().toLowerCase(). Nettoyer uniquement une clé de recherche ne peut pas corriger des clés stockées de façon incohérente.

Compare le contenu des valeurs enveloppées avec equals. Si deux entrées contiennent chacune 1000, leurs références Integer peuvent être différentes : == peut donc être faux même si leurs contenus numériques correspondent. Après avoir vérifié que les deux valeurs sont non nulles, a.equals(b) compare leurs contenus.

Points clés

  • Chaque clé unique est associée à une valeur ; les valeurs peuvent se répéter.
  • put remplace une valeur existante et renvoie la valeur précédente.
  • Un get pour une clé absente renvoie null ; son unboxing provoque une NullPointerException.
  • getOrDefault ne fournit une valeur par défaut que pour une clé absente.
  • Fais correspondre les clés textuelles de façon cohérente et compare le contenu des valeurs enveloppées.

1.2 Parcours les clés, les valeurs et les entrées

Une Map peut répondre à une recherche ponctuelle ou fournir toutes ses données à une boucle. Choisis la vue qui donne les éléments nécessaires à la boucle. Les vues sont liées à la Map : les modifications effectuées par leur intermédiaire peuvent donc aussi modifier la Map.

Choisir les clés, les valeurs ou les entrées

Utilise keySet() pour parcourir les clés. Une recherche dans cette boucle permet de retrouver chaque valeur :

for (String name : phoneBook.keySet()) {
    System.out.println(name + ": " + phoneBook.get(name));
}

Utilise values() lorsque les clés n’ont pas d’importance. Pour les quantités en stock apple 15, pear 7 et fig 3 :

int total = 0;
for (int quantity : stock.values()) {
    total += quantity;
}

La somme devient 25. Les valeurs répétées contribuent chacune séparément : une vue des valeurs n’est pas un ensemble.

Une entrée réunit une clé et sa valeur. Importe java.util.Map et utilise Map.Entry<K, V> avec getKey() et getValue(). Cela évite une seconde recherche :

String best = null;
int bestScore = Integer.MIN_VALUE;
for (Map.Entry<String, Integer> entry : scores.entrySet()) {
    if (best == null || entry.getValue() > bestScore) {
        best = entry.getKey();
        bestScore = entry.getValue();
    }
}

Pour Ana 82, Ben 91 et Cai 77, le résultat est Ben avec 91. Le test best == null traite aussi le cas où le premier score est égal au plus petit int possible. Si la Map est vide, best reste à null.

Choisir explicitement l’ordre

Une HashMap ne garantit aucun ordre de parcours. Tu ne peux pas supposer qu’il s’agit de l’ordre d’insertion, de l’ordre trié ou de l’ordre affiché aujourd’hui. Une LinkedHashMap conserve l’ordre d’insertion ; une TreeMap parcourt les clés triées. Si deux scores sont égaux, la boucle précédente conserve le premier rencontré. Avec une HashMap, l’un ou l’autre des noms à égalité peut gagner. Ajoute une règle explicite de départage lorsque le résultat doit être prévisible.

Supprimer des entrées avec l’itérateur

Appeler stock.remove(key) dans une boucle for-each sur stock.keySet() modifie les clés que parcourt la boucle. Cela peut provoquer une ConcurrentModificationException. La détection n’est pas garantie : une exécution sans exception ne rend pas ce schéma valide.

Utilise la méthode de suppression propre à l’itérateur :

Iterator<Map.Entry<String, Integer>> it =
    stock.entrySet().iterator();
while (it.hasNext()) {
    if (it.next().getValue() == 0) {
        it.remove();
    }
}

Importe java.util.Iterator. Pour apple 15, pear 0, fig 0 et kiwi 4, ce code supprime pear et fig. Une autre approche sûre consiste à noter les clés dans une liste, à terminer la boucle, puis à supprimer ces clés.

Remplacer une valeur existante n’ajoute ni ne supprime de clé. Pendant un parcours des entrées, entry.setValue(entry.getValue() * 2) peut doubler les quantités sans erreur. N’ajoute pas de nouvelles clés par l’intermédiaire de la Map pendant cette boucle.

Distinguer une vue d’une copie

stock.keySet().remove("apple") supprime l’entrée correspondante de la Map. Une liste distincte créée avec new ArrayList<>(stock.keySet()) est une copie des clés présentes à cet instant. Trier cette liste ne réordonne pas la Map, et supprimer un nom de la liste ne supprime pas son association.

Points clés

  • Utilise keySet, values ou entrySet selon les besoins de la boucle.
  • HashMap ne garantit aucun ordre de parcours ; départage explicitement les égalités.
  • Utilise la méthode remove d’un itérateur pour supprimer pendant le parcours.
  • Remplacer une valeur existante est autorisé pendant le parcours.
  • Les vues sont liées à la Map ; une liste de clés copiée en est distincte.

1.3 Utilise tes propres objets comme clés de Map

Un identifiant de produit stocké sous forme de String possède déjà des règles d’égalité adaptées. Pour une clé issue de ta propre classe, tu dois décider si deux objets distincts ayant les mêmes données représentent la même clé.

Les codes de hachage ciblent la recherche ; l’égalité la confirme

Une HashMap utilise hashCode() pour aider à localiser une clé et equals() pour vérifier une correspondance. Des clés égales doivent avoir des codes de hachage égaux. Des clés différentes peuvent partager un code de hachage ; l’égalité permet tout de même de les distinguer. Les classes de valeurs standard comme String et Integer respectent déjà ce contrat.

Sans redéfinition, une classe hérite de Object une égalité fondée sur l’identité. Deux points créés séparément, de coordonnées 2 et 3, sont des clés différentes même si leurs champs correspondent :

labels.put(new Point(2, 3), "door");
String label = labels.get(new Point(2, 3));

Avec l’égalité par identité, label vaut null. La recherche a créé un second objet, différent de celui utilisé pour l’insertion.

Redéfinir les deux méthodes ensemble

Ici, les coordonnées d’un point définissent son contenu :

import java.util.Objects;

final class Point {
    private final int x;
    private final int y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof Point)) {
            return false;
        }
        Point point = (Point) other;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        return Objects.hash(x, y);
    }
}

La vérification d’identité traite rapidement le cas du même objet. La vérification du type rejette null et les objets d’un autre type. La dernière comparaison vérifie les deux coordonnées. Objects.hash(x, y) construit le code de hachage à partir de ces mêmes champs. Avec cette classe, la recherche précédente renvoie "door".

Redéfinir uniquement equals laisse en place la méthode de hachage héritée, qui ne garantit pas des codes de hachage égaux pour des objets distincts dont les champs sont égaux. Une Map peut alors ne pas trouver une clé égale. Un code de hachage constant préserverait la correction du résultat, mais ralentirait la recherche. Générer les deux redéfinitions dans un éditeur aide à éviter d’utiliser des champs différents.

Utiliser la signature exacte de la méthode

public boolean equals(Point other) surcharge la méthode ; elle ne remplace pas equals(Object). La recherche dans une Map utilise equals(Object) : la nouvelle surcharge ne lui donne donc pas une égalité de contenu. L’annotation @Override transforme une signature incorrecte en erreur de compilation, au lieu de laisser un bogue de recherche caché.

Garder stables les éléments qui déterminent l’identité de la clé

Ne modifie pas les champs qui déterminent l’égalité ou le code de hachage d’une clé tant qu’elle est stockée. Si un point stocké passe de (2, 3) à (5, 3), la Map peut ne plus le retrouver sous l’une ou l’autre valeur, même si size() reste inchangée. Supprime-le avant de le modifier, puis réinsère-le. Déclarer les champs de la clé final, comme ci-dessus, empêche cette erreur.

Ces règles déterminent aussi l’appartenance à une HashSet. Une ArrayList utilise equals pour les recherches de contenu comme contains ; elle n’a pas besoin de codes de hachage pour cette recherche.

Points clés

  • Des objets égaux doivent avoir des codes de hachage égaux ; des objets différents peuvent partager un même code.
  • Redéfinis equals(Object) et hashCode() avec les mêmes champs.
  • @Override détecte une surcharge erronée de equals.
  • Ne modifie pas les champs utilisés pour l’égalité et le code de hachage tant qu’une clé est stockée.
2

Compte, regroupe et indexe des données avec des Map

Une Map peut construire des informations utiles pendant qu’un programme lit des données : un effectif pour chaque mot, une liste pour chaque cours ou un objet pour chaque identifiant. Le choix important est ce que représente une valeur. Un nombre accumule un résultat ; une liste ou un ensemble réunit un groupe ; une référence à un objet constitue un index. Suis chaque mise à jour à partir d’une Map vide pour comprendre clairement le comportement lors des premières occurrences, des clés répétées et du partage d’objets.

2.1 Compte les occurrences et calcule les sommes par clé

Un tableau des effectifs possède une clé pour chaque élément distinct et un nombre indiquant ses occurrences. La première occurrence initialise un effectif ; chaque occurrence suivante met à jour cette même entrée.

Construire un effectif élément par élément
HashMap<String, Integer> counts = new HashMap<>();
for (String word : text.split(" ")) {
    int oldCount = counts.getOrDefault(word, 0);
    counts.put(word, oldCount + 1);
}

Pour le texte « the cat saw the dog and the cat ran », le premier "the" est absent : son ancien effectif est donc de 0 et son nouvel effectif de 1. Ses deux apparitions suivantes font passer cette entrée à 2 puis à 3. "cat" termine à 2 ; "saw", "dog", "and" et "ran" terminent chacun à 1.

Il y a 6 mots distincts, donc counts.size() vaut 6. La somme des valeurs est de 9, le nombre d’occurrences de mots. Ces nombres mesurent des choses différentes : la taille de la Map n’est pas la longueur de la séquence d’origine.

La mise à jour peut s’écrire sur une ligne :

counts.put(word, counts.getOrDefault(word, 0) + 1);

Une forme équivalente plus longue vérifie avec containsKey, incrémente un effectif existant et stocke 1 pour une nouvelle clé. Dans ce schéma, tous les effectifs stockés sont non nuls.

Préserver le résultat précédent

Appeler counts.put(word, 1) pour chaque mot remplace à chaque fois l’effectif par 1. Cela enregistre l’existence d’un mot, mais perd son effectif. Appeler counts.get(word) + 1 sans traiter la première occurrence essaie d’effectuer l’unboxing de null et échoue. La valeur par défaut intervient à l’étape de lecture ; l’effectif augmenté doit ensuite être stocké.

Décider ce qui constitue un même élément

L’égalité des chaînes est exacte. "The" et "the" sont des clés différentes, tout comme "cat" et "cat,". Si la tâche les considère comme un même mot, nettoie chaque jeton avant de le compter. Mets le texte en minuscules et supprime la ponctuation que le programme traite comme séparateur. Utilise une règle cohérente pour que les résultats ne dépendent pas de la graphie rencontrée en premier.

La clé peut aussi être un caractère. Avec HashMap<Character, Integer>, une boucle sur "banana".toCharArray() produit a=3, n=2 et b=1 avec le même schéma de lecture, d’augmentation et de stockage.

Accumuler des montants plutôt que des occurrences

Pour les sommes par catégorie, ajoute le montant actuel au lieu de 1 :

HashMap<String, Double> totals = new HashMap<>();
double oldTotal = totals.getOrDefault(category, 0.0);
totals.put(category, oldTotal + amount);

Alimentation 12,50, transport 3,20 et alimentation 7,25 donnent alimentation 19,75 et transport 3,20. La valeur par défaut est 0.0, ce qui correspond au type de valeur Double. La Map conserve une entrée par catégorie, quel que soit le nombre de montants additionnés.

Lire le tableau terminé

Parcours les entrées pour trouver le plus grand effectif ou la plus grande somme, en mémorisant la meilleure clé et sa valeur. Précise une règle de départage si nécessaire. Pour un compte rendu alphabétique, new TreeMap<>(counts) copie les associations en triant les clés. Les effectifs restent inchangés ; trier les clés ne trie pas les catégories selon leurs sommes.

Points clés

  • Une Map d’effectifs stocke un effectif par clé distincte.
  • Lis l’ancien effectif avec zéro comme valeur par défaut, ajoute un et stocke le résultat.
  • La taille de la Map compte les éléments distincts ; la somme des effectifs mesure les occurrences.
  • Normalise le texte de façon cohérente avant de compter.
  • Utilise le même schéma de mise à jour pour additionner des montants par clé.
  • Choisis l’ordre du compte rendu indépendamment des valeurs accumulées.

2.2 Regroupe des valeurs sous une même clé en utilisant des listes et des ensembles comme valeurs

La valeur d’une Map peut être une collection. Lorsque plusieurs étudiants suivent un même cours, le cours est une clé et la liste associée contient tous ses étudiants. La règle d’unicité des clés de la Map s’applique toujours : la liste est l’unique valeur associée à ce cours.

Créer un groupe avant d’y ajouter un élément
HashMap<Character, ArrayList<String>> groups = new HashMap<>();
for (String fruit : fruits) {
    char letter = fruit.charAt(0);
    if (!groups.containsKey(letter)) {
        groups.put(letter, new ArrayList<>());
    }
    groups.get(letter).add(fruit);
}

Pour « apple », « banana », « avocado », « cherry » et « blueberry », le premier fruit crée la liste pour a et y ajoute « apple ». « Banana » crée la liste pour b. « Avocado » trouve la liste a existante et s’y ajoute. Le résultat est a → [apple, avocado], b → [banana, blueberry] et c → [cherry]. Chaque liste conserve son propre ordre d’insertion, même si la HashMap n’ordonne pas ses clés.

La vérification peut être raccourcie :

groups.putIfAbsent(letter, new ArrayList<>());
groups.get(letter).add(fruit);

putIfAbsent conserve une liste existante non nulle. Le get suivant renvoie cette liste, prête pour l’ajout.

Conserver la liste déjà construite

Un groups.put(letter, new ArrayList<>()) inconditionnel dans la boucle remplace l’ancienne liste à chaque occurrence. Seul le dernier fruit de chaque lettre subsiste après le add suivant. L’erreur inverse consiste à sauter entièrement la création : groups.get(letter).add(fruit) lève une NullPointerException pour une nouvelle clé car aucune liste n’existe encore.

Comprendre la référence

get renvoie la référence à la liste stockée. Lui ajouter un élément modifie cette même liste : il n’est donc pas nécessaire de la réinsérer. Cela explique aussi un bogue lié au partage :

ArrayList<String> shared = new ArrayList<>();
courses.put("Art", shared);
courses.put("Music", shared);
courses.get("Art").add("Jin");

Les deux clés mènent maintenant à [Jin]. Les deux clés n’ont pas créé deux listes. Crée une nouvelle liste pour chaque nouveau groupe lorsque les groupes doivent être indépendants.

Choisir des listes ou des ensembles dans les groupes

Une liste conserve les ajouts répétés. Un ensemble empêche les doublons dans ce groupe. Une HashMap<String, HashSet<String>> peut donc réunir les étudiants distincts inscrits à chaque cours sans compter deux fois le même étudiant dans un cours. La règle de l’ensemble s’applique à l’intérieur de chaque valeur ; la Map externe conserve une entrée par cours.

Pour lire un groupe qui peut être absent, vérifie avec containsKey ou utilise groups.getOrDefault(letter, new ArrayList<>()). Une clé absente donne alors une liste vide pour cet appel. La liste par défaut n’est pas automatiquement insérée ; lui ajouter un élément ne crée pas de groupe stocké.

Supprimer le dernier élément d’un groupe laisse la clé associée à une collection vide. Si le programme ne doit plus énumérer les groupes vides, vérifie avec isEmpty() et supprime aussi cette clé. Compte les groupes avec la taille de la Map externe et les éléments avec les tailles des collections internes.

Points clés

  • Assure-toi qu’un groupe existe, puis ajoute un élément à sa liste ou à son ensemble stocké.
  • Crée une nouvelle collection pour chaque groupe indépendant.
  • get renvoie la référence stockée : les modifications internes ne nécessitent donc pas de put supplémentaire.
  • Les valeurs de type liste conservent les répétitions ; celles de type ensemble conservent les éléments distincts du groupe.
  • Un groupe vide stocké conserve une entrée dans la Map.

2.3 Recherche rapidement des objets et des prix avec un index fondé sur une Map

Un index associe une clé d’identification à un objet. Une bibliothèque peut trouver un livre par son ISBN sans parcourir tous les livres d’une liste. Une table de correspondance utilise la même structure pour associer un code à une valeur simple, comme le prix d’un produit.

Choisir une clé d’identification

Une HashMap<String, Book> peut associer un ISBN à son livre. Chaque recherche ne nécessite que la clé. Le nom d’une personne est souvent une mauvaise clé unique : stocker une autre personne appelée « Sam Lee » sous cette même chaîne remplace la personne précédente. Utilise un identifiant unique ou une Map de regroupement si un nom doit mener à plusieurs personnes.

Conserve un index dans la classe responsable des données :

class Library {
    private HashMap<String, Book> byIsbn;

    Library() {
        byIsbn = new HashMap<>();
    }

    void addBook(Book book) {
        byIsbn.put(book.getIsbn(), book);
    }

    Book findByIsbn(String isbn) {
        return byIsbn.get(isbn);
    }
}

Ici, Book fournit une méthode getIsbn(). Les appelants utilisent addBook et findByIsbn ; ils n’ont pas besoin de connaître l’implémentation de la Map stockée. Le champ privé donne aussi à la classe un endroit unique où faire respecter ses règles d’ajout et de remplacement des livres.

Vérifier un résultat absent

Si findByIsbn renvoie null, aucun livre n’a été trouvé. Teste le résultat avant d’appeler une méthode sur celui-ci :

Book found = library.findByIsbn("978-0-00-000000-2");
if (found != null) {
    found.setOnLoan(true);
}

Appeler setOnLoan directement sur un résultat absent lèverait une NullPointerException. Une méthode comme hasBook(isbn) permet aussi aux appelants de vérifier la présence d’une clé.

Suivre les objets partagés entre les index

Une Map stocke une référence à un objet, pas une nouvelle copie de cet objet. Si le même livre figure dans une liste de tous les livres, une Map par ISBN et un regroupement par auteur, setOnLoan(true) modifie l’unique livre auquel les trois structures font référence. Cela évite que trois objets livre distincts divergent.

Les structures de collection elles-mêmes doivent tout de même être mises à jour. Supprimer un livre de la Map par ISBN ne supprime pas sa référence de la liste d’un auteur. Si une bibliothèque conserve les deux index, ses méthodes d’ajout et de suppression doivent mettre à jour les deux. Centraliser ces modifications dans des méthodes comme addBook et removeBook aide à garder des recherches cohérentes.

Utiliser une table dans un calcul

Supposons qu’une table de prix indique café 2,50, thé 2,00 et muffin 3,25. Pour deux cafés et un muffin :

double cost = 2 * prices.get("coffee") + prices.get("muffin");

Le sous-total des cafés est de 5,00 ; ajouter 3,25 donne 8,25. Les clés identifient les produits et les valeurs fournissent les montants. Un produit absent exige une décision explicite avant le calcul : une valeur par défaut de zéro le traiterait comme gratuit sans le signaler. La même technique de recherche peut donc nécessiter une règle différente de celle d’un tableau des effectifs pour les clés absentes.

Points clés

  • Un index trouve des objets à l’aide d’une clé d’identification.
  • Utilise une clé unique ou regroupe explicitement plusieurs objets correspondants.
  • Les index partagent des références aux objets, mais les ajouts et les suppressions doivent mettre à jour chaque index.
  • Garde les Map de données privées et expose des méthodes qui font respecter leurs règles.
3

Conserve des valeurs distinctes avec des ensembles

Parfois, la question est simplement de savoir si une valeur est déjà apparue. Les ensembles répondent directement à cette question et peuvent aussi comparer des groupes de valeurs, comme les personnes participant à deux événements. L’absence de doublons change à la fois le code que tu écris et la signification de la taille finale. Commence par l’appartenance, puis combine des ensembles et choisis si leurs valeurs doivent apparaître dans l’ordre d’insertion ou dans un ordre trié.

3.1 Stocke des valeurs distinctes et teste l’appartenance avec HashSet

Un ensemble contient chaque valeur au plus une fois. Il convient aux questions comme « Cette valeur est-elle déjà apparue ? » ou « Combien de valeurs différentes sont présentes ? ». Une HashSet permet de vérifier rapidement l’appartenance en moyenne, sans garantir d’ordre d’affichage.

Ajouter et vérifier des valeurs
import java.util.HashSet;

HashSet<String> visited = new HashSet<>();
boolean first = visited.add("Oslo");
boolean second = visited.add("Lima");
boolean third = visited.add("Oslo");
visited.add("Pune");

Les trois booléens stockés sont true, true et false. Le second « Oslo » correspond à un élément existant et n’est donc pas ajouté. La taille de l’ensemble est de 3. L’ajout d’un doublon ne remplace pas une case numérotée, car un ensemble n’a pas d’indice.

visited.contains("Lima") renvoie true. visited.remove("Lima") le supprime et renvoie true ; répéter cette suppression renvoie false. Utilise une boucle for-each pour parcourir les valeurs. Il n’existe pas de get(0) pour obtenir la première valeur d’une HashSet.

Supprimer les doublons d’une liste
ArrayList<Integer> values = new ArrayList<>();
values.add(3);
values.add(1);
values.add(3);
values.add(2);
values.add(1);
HashSet<Integer> distinct = new HashSet<>(values);

L’ensemble contient trois valeurs : {1, 2, 3}. Son ordre de parcours réel n’est pas spécifié. La liste source contient toujours cinq éléments car le constructeur crée une collection distincte.

Utilise new LinkedHashSet<>(values) pour conserver l’ordre des premières occurrences, ce qui donne 3, 1, 2. Utilise new TreeSet<>(values) pour obtenir les valeurs triées, 1, 2, 3. Les ensembles sont écrits ici entre accolades pour souligner l’appartenance ; la méthode toString() standard des ensembles en Java utilise des crochets.

Détecter la première répétition

Le résultat de add peut effectuer ensemble le test d’appartenance et l’insertion :

HashSet<Integer> seen = new HashSet<>();
for (int number : numbers) {
    if (!seen.add(number)) {
        System.out.println(number);
        break;
    }
}

Pour [4, 7, 2, 7, 4], la boucle affiche 7. C’est la première valeur rencontrée une seconde fois, même si 4 est apparu plus tôt dans la séquence. Avant que 7 se répète, l’ensemble contient 4, 7 et 2. L’échec de l’insertion déclenche l’arrêt.

Savoir ce qu’un ensemble ne peut pas indiquer

Vérifier avec contains avant chaque add est inutile car add traite déjà les doublons. Une liste accompagnée d’une vérification avec contains peut aussi conserver des valeurs distinctes, mais chaque recherche dans la liste peut parcourir tous les éléments stockés. Une HashSet exprime directement la règle.

L’égalité compte pour tes propres objets. Une HashSet<Point> a besoin d’une méthode equals fondée sur le contenu et d’un hashCode cohérent pour réunir des points créés séparément avec les mêmes coordonnées. Sans ces redéfinitions, des instances distinctes restent des éléments distincts.

Enfin, size() mesure les valeurs distinctes, pas les occurrences. Les neuf mots de « the cat saw the dog and the cat ran » produisent six mots distincts. Un ensemble ne permet plus de savoir que « the » est apparu trois fois ; utilise une Map d’effectifs lorsque ces effectifs comptent.

Points clés

  • HashSet stocke des valeurs distinctes sans indice ni ordre garanti.
  • add renvoie false lorsqu’une valeur égale est déjà présente.
  • Un ensemble copié supprime les doublons sans modifier la liste source.
  • Utilise le résultat de add pour détecter une valeur répétée.
  • La taille d’un ensemble compte les valeurs distinctes ; les effectifs nécessitent une Map.

3.2 Combine des ensembles et préserve leur ordre

Les ensembles peuvent décrire des groupes et comparer leur appartenance. Si deux listes de participants à des événements contiennent plusieurs fois la même personne, un ensemble réduit d’abord chaque liste aux personnes présentes. Les opérations ensemblistes répondent ensuite aux questions portant sur l’un ou l’autre événement, les deux ou un seul.

Combiner deux groupes

Soit lundi {Ana, Ben, Cai, Dee} et mardi {Ben, Dee, Eva}.

QuestionMéthode sur une copie de lundiRésultat
Qui a participé à au moins l’une des deux journées ?addAll(tuesday){Ana, Ben, Cai, Dee, Eva}
Qui a participé aux deux journées ?retainAll(tuesday){Ben, Dee}
Qui a participé uniquement le lundi ?removeAll(tuesday){Ana, Cai}

Ces opérations sont l’union, l’intersection et la différence. Elles modifient l’ensemble receveur et renvoient un booléen indiquant s’il a changé. Elles ne renvoient pas un nouvel ensemble de résultats.

Préserver l’original

Fais une copie avant de modifier l’appartenance si tu as encore besoin de lundi :

HashSet<String> both = new HashSet<>(monday);
both.retainAll(tuesday);

both commence avec les quatre noms du lundi. retainAll supprime Ana et Cai car elles ne figurent pas dans mardi. Lundi lui-même reste inchangé. Pour trouver les personnes présentes uniquement le mardi, commence par une copie de mardi et supprime les noms du lundi : tu obtiens {Eva}. La différence a un sens ; l’inverser change la question.

Vérifier les sous-ensembles et l’égalité

monday.containsAll(group) vérifie si toutes les valeurs de group sont présentes dans lundi. Pour {Ben, Dee}, la méthode renvoie true : ce groupe est un sous-ensemble de lundi. Elle n’exige pas que lundi contienne uniquement ces deux personnes.

Deux ensembles sont égaux lorsque leurs éléments correspondent, quels que soient leur ordre d’insertion ou leur implémentation. Une HashSet contenant « x » et « y » est égale à une TreeSet contenant « y » et « x ». L’appartenance détermine l’égalité des ensembles : l’ordre seul ne peut donc pas les rendre différents.

Choisir un ordre de parcours
ImplémentationOrdre de parcours des éléments
HashSetAucune garantie
LinkedHashSetOrdre d’insertion
TreeSetOrdre trié

Les trois évitent les doublons. Utilise LinkedHashSet lorsque la première apparition de chaque nom compte. Utilise TreeSet lorsque chaque parcours doit déjà être trié. Pour les chaînes, le tri naturel suit les codes de caractères : les formes minuscules et majuscules ne se comportent pas comme dans un alphabet unique insensible à la casse.

Une TreeSet créée avec son constructeur par défaut nécessite des éléments possédant une comparaison naturelle, comme des chaînes, des nombres ou des objets qui implémentent Comparable. Dans cet ensemble, un résultat de comparaison égal à zéro indique un doublon. Une classe qui ne fournit aucune comparaison naturelle provoque une ClassCastException lors de l’insertion. Fournir un comparateur explicite est une autre façon de définir l’ordre d’une collection arborescente ; les exemples avec les réglages par défaut utilisent l’ordre naturel.

Points clés

  • addAll, retainAll et removeAll modifient l’ensemble receveur.
  • Copie d’abord un ensemble si tu as encore besoin de ses éléments d’origine.
  • containsAll vérifie un sous-ensemble ; l’égalité des ensembles ne tient pas compte de l’ordre.
  • Choisis une implémentation fondée sur le hachage, chaînée ou arborescente selon que tu souhaites un ordre non spécifié, l’ordre d’insertion ou un ordre trié.
4

Programme avec les interfaces List, Set et Map

Le type à gauche d’une déclaration de collection indique au reste du programme les opérations qu’il peut utiliser. La classe à droite fournit ces opérations et peut garantir un ordre particulier. Apprendre à lire les deux côtés rend le code utilisant des collections plus facile à modifier et les méthodes plus faciles à réutiliser. Cela aide aussi à comprendre pourquoi une liste, un ensemble et une Map se comportent différemment même lorsqu’ils contiennent des données d’apparence similaire.

4.1 Déclare des variables et des paramètres de type interface

Une interface décrit les opérations fournies par une classe qui l’implémente. Elle permet au type d’une variable d’indiquer ce dont le code a besoin tout en laissant le choix du stockage à une classe concrète. List, Set et Map sont des interfaces liées aux collections dans java.util.

Lire les deux côtés d’une déclaration
List<String> names = new ArrayList<>();
Set<String> tags = new HashSet<>();
Map<String, Integer> counts = new HashMap<>();

Le côté gauche déclare le type de la variable. Le côté droit crée un objet d’une classe qui implémente ce type. Importe les deux types, par exemple java.util.List et java.util.ArrayList. Tu ne peux pas écrire new List<>() ou new Map<>() : une interface n’est pas un objet concret à construire.

Le code qui utilise counts peut appeler put, get et entrySet car Map les déclare. Si des clés classées par ordre alphabétique deviennent utiles, remplace la construction par new TreeMap<>(). Les appels existants se compilent toujours. Leur ordre peut changer car les implémentations peuvent garantir des ordres différents ; l’interface ne rend pas tous leurs comportements identiques.

Accepter la capacité nécessaire à une méthode

Une méthode qui ne fait que compter les mots longs peut accepter une Collection :

static int countLong(Collection<String> words, int min) {
    int count = 0;
    for (String word : words) {
        if (word.length() >= min) {
            count++;
        }
    }
    return count;
}

Pour [« a », « tree », « house »] et un minimum de 4, elle renvoie 2. La même méthode peut recevoir une ArrayList, une LinkedList, une HashSet ou List.of(...) car elle ne fait que lire les éléments. Un ensemble peut avoir déjà supprimé des doublons et fournir ainsi des données d’entrée différentes de celles d’une liste.

Utiliser un paramètre de type interface évite d’imposer une classe de stockage particulière lorsque la méthode n’en a pas besoin. Si les positions sont nécessaires, accepte List. Si la recherche par clé est nécessaire, accepte Map.

Connaître les limites du type déclaré
List<String> names = new ArrayList<>();
names.ensureCapacity(100);  // does not compile

L’objet est une ArrayList, mais List ne déclare pas ensureCapacity. Le compilateur vérifie le type déclaré de la variable. Utilise un type de classe concrète lorsque son opération particulière est réellement nécessaire ; ne modifie pas les paramètres de liste ordinaires simplement pour les faire correspondre à la classe d’un appelant.

Situer Map par rapport à Collection

List et Set étendent Collection, qui décrit un groupe d’éléments. Cette interface déclare des méthodes comme add, remove, contains, size, isEmpty, addAll et clear. La prise en charge d’une modification dépend de la collection effective.

Map n’étend pas Collection. Elle stocke des associations et fournit des vues qui sont des collections : keySet() est un Set, values() est une Collection et entrySet() est un Set d’entrées. Transmets counts.values() à une méthode qui attend une collection de valeurs, pas counts elle-même.

Une classe peut implémenter plusieurs interfaces. LinkedList implémente à la fois List et Deque, une interface de file à double extrémité. Ta propre classe indique les interfaces qu’elle s’engage à implémenter après implements, comme dans class Member implements Comparable<Member>.

Points clés

  • Déclare l’interface nécessaire à gauche et construis une classe qui l’implémente à droite.
  • Les paramètres de type interface acceptent différentes implémentations qui fournissent les opérations nécessaires.
  • Une variable n’expose que les méthodes déclarées par son type.
  • List et Set étendent Collection ; Map fournit des vues qui sont des collections.

4.2 Identifie les garanties de List, Set et Map

Choisis une interface selon les règles dont tes données ont besoin. Des contenus d’apparence similaire ne rendent pas une liste, un ensemble et une Map interchangeables : chacun donne un sens différent aux positions, aux répétitions et à l’égalité.

Comparer les garanties
InterfaceContenu stockéRègle importante
ListÉléments à des positions numérotées à partir de 0Les éléments répétés sont autorisés
SetÉléments distinctsAucune opération get par indice
MapPaires clé–valeurLes clés sont uniques ; les valeurs peuvent se répéter

ArrayList et LinkedList implémentent List. HashSet, LinkedHashSet et TreeSet implémentent Set. HashMap, LinkedHashMap et TreeMap implémentent Map. Les versions fondées sur le hachage ne garantissent aucun ordre de parcours ; les versions chaînées conservent l’ordre d’insertion ; les versions arborescentes maintiennent les éléments ou les clés triés. Réinsérer une clé existante dans une LinkedHashMap ordinaire qui suit l’ordre d’insertion conserve sa place.

Examiner la suppression dans une liste d’entiers

Une List<Integer> possède deux surcharges pertinentes :

List<Integer> numbers = new ArrayList<>(List.of(1, 5, 7));
numbers.remove(1);

L’argument 1 est un int, donc Java supprime l’élément d’indice 1 : la valeur 5. Le résultat est [1, 7]. En repartant de [1, 5, 7], numbers.remove(Integer.valueOf(1)) sélectionne la suppression par valeur et laisse [5, 7]. L’objet enveloppe désigne clairement la surcharge voulue.

Comparer les contenus avec la bonne règle

Deux listes sont égales lorsque les mêmes éléments apparaissent dans le même ordre. Une ArrayList [1, 2] est égale à une LinkedList [1, 2], mais pas à une liste [2, 1]. Deux ensembles comparent l’appartenance, sans tenir compte de l’ordre. Deux Map comparent les associations : l’ordre d’insertion ne modifie donc pas leur égalité. Leurs classes concrètes peuvent différer alors que leurs contenus sont égaux selon la règle de l’interface.

Reconnaître les collections non modifiables
List<String> labels = List.of("a", "b");
Set<Integer> levels = Set.of(1, 2, 3);
Map<String, Double> prices = Map.of("tea", 2.0, "coffee", 2.5);

Ces fabriques renvoient des collections non modifiables. Toute tentative d’ajouter, de supprimer, de remplacer ou de trier leur contenu lève UnsupportedOperationException. Map.of accepte jusqu’à dix paires clé–valeur.

Les trois rejettent les éléments, clés ou valeurs null en levant NullPointerException. Set.of rejette les éléments en double et Map.of rejette les clés en double en levant IllegalArgumentException. List.of autorise les doublons car une liste peut répéter un élément. L’ordre de parcours des ensembles et des Map issus de ces fabriques n’est pas spécifié.

Copier lorsqu’une modification est nécessaire

new ArrayList<>(labels) crée une liste modifiable contenant les mêmes éléments. new HashSet<>(someList) et new HashMap<>(someMap) créent de même des structures de collection distinctes.

Ces copies sont superficielles : elles contiennent les mêmes références aux éléments. Supprimer un élément d’une copie laisse la structure d’origine intacte, mais modifier un objet mutable par l’une ou l’autre collection modifie l’objet partagé. Une collection non modifiable empêche les modifications de sa structure ; elle ne fige pas tous les objets qu’elle contient.

Points clés

  • Les listes ont des positions et autorisent les doublons ; les ensembles contiennent des éléments distincts ; les Map ont des clés uniques.
  • remove(1) sur une liste d’entiers supprime l’élément d’un indice ; remove(Integer.valueOf(1)) supprime une valeur.
  • L’égalité des listes vérifie l’ordre ; celle des ensembles et des Map vérifie le contenu sans tenir compte de l’ordre d’insertion.
  • Les fabriques of créent des collections non modifiables et rejettent les valeurs nulles.
  • Set.of rejette les éléments en double ; Map.of rejette les clés en double.
  • Une copie modifiable possède une structure de collection distincte, mais partage les références aux éléments.
5

Trie des collections avec Comparable

Le tri place les valeurs dans un ordre que le reste du code peut utiliser. Les nombres et les chaînes connaissent déjà leur ordre naturel ; les objets de tes propres classes ont besoin d’une règle explicite. Suis le tri d’une liste, puis écris une comparaison qui traite sans erreur les nombres, le texte et les égalités. Cette règle compte aussi en dehors des listes : un ensemble ou une Map triés l’utilisent pour déterminer quand deux éléments ou clés occupent la même place.

5.1 Trie des listes de nombres et de chaînes

Une liste conserve un ordre, mais celui-ci peut simplement refléter l’arrivée des valeurs. Le tri réorganise la liste selon une règle de comparaison. Java fournit déjà un ordre naturel pour les nombres et les chaînes.

Trier une liste modifiable en place
List<Double> values = new ArrayList<>(List.of(3.5, -1.0, 2.25));
Collections.sort(values);

Importe java.util.Collections. La même liste contient maintenant [-1,0 ; 2,25 ; 3,5]. Le tri renvoie void, donc values = Collections.sort(values) ne se compile pas. values.sort(null) trie aussi dans l’ordre naturel. Pour un tableau, utilise Arrays.sort(array) ; un tableau contenant 5, 2 et 8 devient 2, 5, 8.

Prévoir l’ordre des chaînes caractère par caractère

La comparaison de chaînes examine le premier caractère qui diffère. Si une chaîne est le début d’une autre, la plus courte vient en premier. Ainsi, « apple » précède « apples ».

La liste [« pear », « Banana », « apple », « 10 », « 9 »] devient après tri [« 10 », « 9 », « Banana », « apple », « pear »]. Pour ces caractères, les chiffres précèdent les lettres majuscules, qui précèdent les minuscules. « 10 » précède « 9 » car '1' précède '9' ; l’ordre des chaînes n’interprète pas les chaînes de chiffres comme des nombres entiers. Stocke les données numériques sous forme de nombres lorsqu’un ordre numérique est nécessaire.

Utiliser des ordres différents prêts à l’emploi
names.sort(String.CASE_INSENSITIVE_ORDER);
values.sort(Collections.reverseOrder());

Le premier appel classe [« pear », « Banana », « apple »] dans l’ordre [« apple », « Banana », « pear »] sans modifier la casse stockée. Le second utilise l’ordre naturel décroissant. Les nombres 4, 9 et 1 deviennent 9, 4 et 1. Ces arguments sont des comparateurs, des objets qui fournissent un autre ordre.

Collections.reverse(list) inverse simplement la séquence actuelle. La méthode produit un ordre décroissant si cette séquence était déjà triée par ordre croissant ; elle ne trie pas à elle seule une liste quelconque.

Conserver la stabilité en cas d’égalité

Le tri des listes est stable : les éléments considérés comme égaux lors de la comparaison conservent leur ordre relatif précédent. Si une comparaison fondée uniquement sur le score met deux personnes à égalité, leur ordre antérieur dans la liste reste inchangé. La stabilité préserve cet ordre d’entrée ; elle n’invente pas de critère de départage alphabétique.

Reconnaître les échecs et les méthodes pratiques

Une liste issue de List.of(...) ne peut pas être triée en place. Copie-la d’abord dans une ArrayList. Pour une classe qui n’implémente pas Comparable, Collections.sort(list) échoue à la vérification des types lors de la compilation. Appeler list.sort(null) sur de tels objets échoue à l’exécution avec une ClassCastException lorsqu’une comparaison est nécessaire.

Collections.max(collection) et Collections.min(collection) trouvent le plus grand et le plus petit élément dans l’ordre naturel sans réorganiser la collection. Elles lèvent une NoSuchElementException pour une collection vide.

Pour obtenir les clés triées d’une Map, copie map.keySet() dans une ArrayList et trie la copie, ou utilise une TreeMap. Trier une copie de la liste des clés laisse inchangé l’ordre de parcours propre à la Map.

Points clés

  • Collections.sort modifie une liste modifiable en place et renvoie void.
  • L’ordre naturel des chaînes compare les caractères, pas les valeurs numériques écrites en texte.
  • Utilise des comparateurs prêts à l’emploi pour obtenir l’ordre inverse ou ignorer la casse.
  • Un tri stable préserve l’ordre relatif antérieur des éléments à égalité.
  • Copie une liste non modifiable avant de la trier.
  • min et max trouvent les extrema sans trier.

5.2 Implémente Comparable dans ta propre classe

Java ne peut pas deviner si un membre doit être classé selon son nom, sa taille ou un autre champ. Implémente Comparable pour donner à la classe un ordre naturel. Le code de tri peut alors demander à chaque objet de se comparer à un autre objet de cette classe.

Écrire la méthode de comparaison
class Member implements Comparable<Member> {
    private String name;
    private int height;

    Member(String name, int height) {
        this.name = name;
        this.height = height;
    }

    @Override
    public int compareTo(Member other) {
        return Integer.compare(this.height, other.height);
    }
}

La taille est mesurée en centimètres. Comparable<Member> précise que l’autre objet est un Member ; aucun transtypage n’est nécessaire. public int compareTo(Member other) est la méthode requise. L’interface standard Comparable se trouve dans java.lang : aucune importation n’est donc nécessaire pour l’utiliser.

Pour a.compareTo(b), un résultat négatif place a avant b, zéro les place au même rang dans la comparaison et un résultat positif place a après b. Seul le signe compte : -35 est un résultat négatif aussi valide que -1.

Suivre l’ordre

Avec la comparaison des tailles, Ana 172, Ben 165 et Cai 180 sont triés en Ben 165, Ana 172 et Cai 180. Pour placer les membres les plus grands en premier, inverse les arguments :

return Integer.compare(other.height, this.height);

Modifie la règle délibérément. Inverser les arguments inverse le sens de l’ordre pour ce champ ; cela ne change pas la signification de la taille ni les données d’un membre.

Comparer des valeurs numériques entières sans erreur

La soustraction semble pratique, mais elle peut renvoyer le mauvais signe lorsqu’un int dépasse sa capacité. Pour -2 000 000 000 et 2 000 000 000, soustraire le second du premier produit par dépassement 294 967 296, un résultat positif. Integer.compare renvoie correctement un résultat négatif.

Pour les champs décimaux, utilise Double.compare(this.price, other.price). Transtyper une différence en int fait perdre de l’information : (int) (1.8 - 1.5) vaut 0, donc des prix différents deviennent égaux dans la comparaison. Une méthode de comparaison préserve l’ordre sans tronquer la différence.

Comparer du texte et réutiliser la règle

Pour ordonner par nom, renvoie this.name.compareTo(other.name). Cette méthode suit l’ordre des caractères des chaînes. compareToIgnoreCase fournit une comparaison textuelle insensible à la casse lorsque c’est la règle souhaitée pour le champ.

Une fois qu’une classe définit un ordre naturel, des opérations comme Collections.sort, Collections.max et les comparaisons par défaut de TreeSet ou de TreeMap peuvent l’utiliser. Une classe peut aussi implémenter d’autres interfaces, séparées par des virgules après implements.

La classe possède un seul ordre naturel : un compareTo différent n’est pas choisi pour chaque liste. Utilise des objets comparateurs distincts lorsqu’un contexte exige un ordre par nom et un autre un ordre par taille. Une comparaison fondée uniquement sur la taille met aussi à égalité toutes les tailles égales ; décider si cette égalité est acceptable devient particulièrement important dans les ensembles triés.

Points clés

  • Implémente Comparable<YourClass> avec une méthode compareTo publique.
  • Un résultat négatif, nul ou positif signifie respectivement avant, à égalité ou après.
  • Utilise Integer.compare et Double.compare pour ordonner les nombres sans erreur.
  • Inverse les arguments de comparaison pour inverser le sens de l’ordre d’un champ.
  • Une classe possède un seul ordre naturel ; les comparateurs fournissent d’autres ordres.

5.3 Départage les égalités et utilise des ensembles et des Map triés

Une comparaison principale laisse souvent des égalités. Deux films peuvent avoir la même année ou deux joueurs le même score. Un critère de départage ne fait intervenir le champ suivant que lorsque les champs précédents sont égaux dans la comparaison.

Comparer les champs par ordre de priorité
@Override
public int compareTo(Film other) {
    int byYear = Integer.compare(this.year, other.year);
    if (byYear != 0) {
        return byYear;
    }
    return this.title.compareTo(other.title);
}

L’année est le critère principal. Le titre ne compte que si les années sont égales. Up (2009), Avatar (2009) et Alien (1979) sont triés en Alien (1979), Avatar (2009), Up (2009). Comparer d’abord les titres leur donnerait la priorité sur l’année et répondrait à une autre tâche de tri.

Le sens de l’ordre peut différer selon le champ. Pour les points du plus élevé au plus faible et les noms de A à Z, commence par Integer.compare(other.points, this.points). Si le résultat est zéro, renvoie this.name.compareTo(other.name). Inverser toute la liste finale inverserait aussi les noms parmi les scores à égalité.

Comprendre la règle des doublons d’un ensemble trié

Une TreeSet<Member> utilisée avec ses réglages par défaut emploie la comparaison naturelle à la fois pour ordonner les éléments et pour déterminer si un élément est déjà présent. Si Member.compareTo n’utilise que la taille, la comparaison d’Ana 172 et de Dee 172 donne zéro. Ajouter Ana renvoie true ; ajouter Dee renvoie false. Ana reste l’élément stocké, même si equals considère les deux membres comme différents.

Une liste peut conserver les deux objets à égalité ; un ensemble arborescent leur donne un seul rang dans la comparaison. Ajoute le critère de départage nécessaire s’ils doivent être distincts dans l’ensemble.

Rendre la comparaison cohérente avec l’égalité

Un ordre est cohérent avec equals lorsque la comparaison renvoie zéro si et seulement si equals renvoie true. Pour une classe dont l’égalité utilise la taille et le nom, comparer la taille puis le nom peut respecter cette règle. Si l’égalité repose sur une autre identité, comme un identifiant de membre, ajouter uniquement le nom comme critère de départage ne garantit pas cette cohérence.

La comparaison doit aussi se comporter comme un ordre valide. Si a précède b, la comparaison inverse doit placer b après a. Si a précède b et b précède c, a doit précéder c. Utiliser des méthodes qui comparent les champs dans leur intégralité selon un ordre de priorité fixe aide à respecter ces règles. Une méthode incohérente peut produire un ordre incorrect ou provoquer une IllegalArgumentException lors du tri.

Garder aussi les clés d’une Map triées

Une TreeMap trie les clés, pas les valeurs. Pour les effectifs des mots de « the cat saw the dog and the cat ran », la première clé est « and » et la dernière est « the ». firstKey() et lastKey() fournissent ces clés extrêmes. Déclare une TreeMap ou une interface de Map triée appropriée pour appeler des méthodes qu’une simple Map ne déclare pas.

La comparaison des clés définit aussi les clés correspondantes. Une seconde clé dont la comparaison donne zéro met à jour l’association existante, même si equals distingue les objets. Les collections arborescentes utilisées avec leurs réglages par défaut exigent des éléments ou des clés naturellement comparables ; insérer un objet sans comparaison adaptée lève ClassCastException. Un comparateur fourni explicitement peut définir un autre ordre.

Points clés

  • Compare d’abord le champ principal et ne consulte les champs suivants qu’en cas d’égalité.
  • Inverse uniquement les champs qui doivent suivre un ordre décroissant.
  • Les collections arborescentes traitent un résultat de comparaison nul comme le même élément ou la même clé.
  • La cohérence avec equals exige que la comparaison donne zéro exactement lorsque l’égalité est vraie.
  • TreeMap trie les clés ; ses méthodes de recherche des extrémités renvoient les clés extrêmes.
  • Une comparaison doit inverser les signes de façon cohérente et préserver l’ordre entre trois éléments.
6

Choisis la collection adaptée à une tâche

Le choix d’une collection commence par les questions auxquelles le programme doit répondre : par position, par appartenance ou par une clé distincte. L’ordre et les doublons précisent encore ce choix. Une fois les données adaptées à la tâche, compare comment les opérations fréquentes évoluent lorsque le nombre de valeurs augmente. Une petite modification, comme créer un ensemble avant une boucle, peut supprimer des recherches répétées sans rendre le programme plus difficile à lire.

6.1 Compare le coût des opérations courantes sur les collections

Le coût d’une opération décrit comment le travail qu’elle demande augmente avec le nombre d’éléments stockés. Il aide à repérer un code rapide pour un petit exemple, mais lent lorsque la collection devient grande.

Comparer la croissance, pas les secondes

Un temps constant, O(1), reste approximativement indépendant de la taille de la collection. Un temps linéaire, O(n), peut augmenter proportionnellement au nombre d’éléments. Un temps logarithmique, O(log n), augmente lentement lorsque la taille grandit. Ces termes décrivent la croissance, pas les temps d’exécution exacts sur un ordinateur particulier.

CollectionOpérationCoût
ArrayListget(i), set(i, x)Constant
ArrayListAjout en fin de listeConstant en moyenne
ArrayListcontains, indexOf, suppression par valeurLinéaire
ArrayListInsertion ou suppression près du débutLinéaire
HashMap / HashSetRecherche par clé ou test d’appartenance, insertion, suppressionConstant en moyenne si les codes de hachage sont bien répartis
TreeMap / TreeSetRecherche, insertion, suppressionLogarithmique
LinkedListAjout ou suppression à l’une ou l’autre extrémitéConstant
LinkedListget(i) en généralLinéaire

Une recherche dans une ArrayList peut vérifier chaque élément ; les modifications près du début décalent les éléments suivants. Une LinkedList doit parcourir la liste jusqu’à une position : des accès répétés par indice peuvent donc être coûteux. ArrayList est un choix par défaut utile pour les opérations ordinaires sur les listes.

Repérer les parcours répétés

Supposons qu’un programme vérifie 10 000 noms dans une liste contenant 100 000 noms. Appeler list.contains(name) pour chaque nom peut nécessiter jusqu’à 1 000 000 000 vérifications d’égalité. Un appel de méthode qui semble rapide reste une recherche complète lorsqu’il est utilisé ainsi.

Construis une fois un ensemble pour les tests d’appartenance :

Set<String> allowed = new HashSet<>(allowedNames);
int matches = 0;
for (String name : incomingNames) {
    if (allowed.contains(name)) {
        matches++;
    }
}

La construction de l’ensemble de 100 000 éléments demande du travail, puis viennent 10 000 tests d’appartenance en temps constant en moyenne. En comptant les deux étapes, le travail total augmente approximativement avec la somme des tailles des deux entrées, plutôt qu’avec leur produit. Reconstruire l’ensemble dans la boucle répéterait le travail de mise en place et supprimerait cet avantage.

Bien comprendre les garanties en moyenne

Les opérations fondées sur le hachage reposent sur des clés dont les codes de hachage répartissent bien les valeurs. Renvoyer un seul code de hachage constant pour chaque objet peut toujours respecter la règle d’égalité, mais ralentit la recherche. Ce n’est pas une solution gratuite pour éviter d’écrire une méthode de hachage utile.

Les collections arborescentes maintiennent un ordre trié avec des opérations de base en temps logarithmique. Doubler le nombre d’éléments n’ajoute qu’une petite quantité de travail de recherche. Pour 100 000 éléments, le logarithme en base deux est d’environ 16,6 ; cela indique l’ordre de grandeur de la recherche, sans garantir exactement 17 comparaisons pour chaque recherche dans un arbre Java.

Tenir compte de toute la tâche

Construire un ensemble supplémentaire coûte du temps et de la mémoire. Pour quelques éléments ou une seule recherche, la liste d’origine peut suffire. Pour des tests d’appartenance répétés, un ensemble réutilisable supprime souvent le coût principal. Pars du comportement nécessaire, puis examine les opérations répétées le plus souvent.

Points clés

  • Les termes de croissance décrivent l’évolution du coût, pas un nombre de secondes mesuré.
  • ArrayList offre un accès rapide par indice, mais les recherches et les modifications près du début sont linéaires.
  • Les recherches par hachage sont en temps constant en moyenne avec des codes de hachage adaptés ; les recherches dans un arbre sont logarithmiques.
  • Construis une fois un ensemble pour remplacer les parcours répétés d’une liste lors des tests d’appartenance.
  • Inclus le temps de mise en place et la mémoire dans la comparaison de solutions complètes.

6.2 Choisis une collection qui répond aux besoins de la tâche

La bonne collection conserve les informations nécessaires au programme et facilite l’expression de ses principales questions. Définis les règles des données avant de choisir le nom d’une classe familière.

Déterminer ce qui identifie un élément
Besoin principalChoix de départExemple
Trouver une valeur par une clé distincteMapCode produit associé à un prix
Tester l’appartenance sans doublonsSetNoms d’utilisateur déjà pris
Conserver des positions, un ordre ou des éléments répétésListListe de lecture qui répète des morceaux
Conserver un nombre fixe de casesTableauDouze mesures mensuelles de précipitations

Un double[12] peut contenir les précipitations en millimètres lorsque le mois de chaque case est connu. Une Map dont les seules clés sont les positions 0, 1, 2 et ainsi de suite ajoute une couche qu’une liste ou un tableau fournit déjà.

Choisir l’ordre nécessaire

Pour les Map et les ensembles, utilise HashMap ou HashSet si aucun ordre n’est nécessaire, LinkedHashMap ou LinkedHashSet pour l’ordre d’insertion, et TreeMap ou TreeSet pour des clés ou éléments triés. Pour une liste polyvalente, commence par ArrayList.

Les effectifs de mots affichés par ordre alphabétique conviennent à une TreeMap<String, Integer>. Une LinkedHashSet<String> convient à une liste de mots-clés distincts dans l’ordre de leur première apparition. Les morceaux répétés nécessitent une liste, même s’ils sont aussi stockés ailleurs dans un ensemble : supprimer les répétitions changerait la liste de lecture.

Combiner les collections lorsque les données ont plusieurs niveaux

Les étudiants par cours peuvent être représentés par une Map<String, List<String>> ; chaque valeur est une liste ordonnée d’inscriptions. Les mots-clés par article peuvent être représentés par une Map<String, Set<String>> ; chaque article reçoit des mots-clés distincts. Un classement peut être une List<Player> triée selon la comparaison naturelle des joueurs.

Les choix externe et interne répondent à des questions différentes. Si les cours doivent être énumérés par ordre alphabétique et les étudiants conservés dans l’ordre d’inscription, utilise une TreeMap à l’extérieur et une liste à l’intérieur. Trier les clés ne trie pas les listes. Si les inscriptions en double doivent être ignorées, utilise plutôt un ensemble pour les groupes internes.

Garder ensemble les données liées

Deux listes parallèles, l’une pour les noms et l’autre pour les numéros de téléphone, reposent sur la correspondance des positions. Supprimer un nom sans son numéro rompt toutes les associations suivantes. Si les noms identifient les personnes de façon unique, une Map peut conserver l’association. Si les noms se répètent ou si plusieurs champs concernent une personne, conserve des objets représentant les personnes dans une liste ou indexe-les par un identifiant unique.

Rechercher sans cesse dans une liste selon un champ est un autre signe qu’il faut envisager un index fondé sur une Map. Conserve aussi la liste si l’ordre d’affichage et les entrées répétées comptent, mais maintiens les deux structures ensemble lors des ajouts ou des suppressions de données.

Vérifier les règles des éléments et le type déclaré

Utilise une déclaration avec un type interface comme Map<String, Double> prices = new HashMap<>(); pour que les appelants s’appuient sur les opérations de Map dont ils ont besoin. Les collections fondées sur le hachage nécessitent une égalité adaptée et des codes de hachage cohérents pour les clés ou éléments personnalisés. Les collections arborescentes utilisées avec leurs réglages par défaut nécessitent une comparaison naturelle qui distingue exactement les valeurs que la collection doit conserver. Ces règles permettent à la collection choisie de représenter les données voulues.

Points clés

  • Choisis les Map pour la recherche par clé, les ensembles pour l’appartenance et les listes pour les positions ou les répétitions.
  • Les tableaux peuvent contenir un nombre fixe de cases, y compris pour des valeurs primitives.
  • Choisis délibérément entre l’ordre d’insertion et un ordre trié.
  • Les collections imbriquées permettent aux clés externes et aux groupes internes de suivre des règles différentes.
  • Garde les champs liés ensemble et maintiens plusieurs index à l’aide de méthodes communes.
  • Adapte les règles d’égalité et de comparaison aux valeurs que la collection doit conserver.

HashMap et collections en Java : exemples

6 Leçons Interactives

1

Suis une Map de stocks, du stockage à la recherche

13 étapes
Suis les modifications, examine les entrées sans erreur et rends des clés personnalisées recherchables.
  1. 1
    IntroductionPars d’une question sur un produit

    Un programme de gestion des stocks doit répondre à la question « Combien de dossiers sont disponibles ? ». Une Map fait du nom du produit la clé et de sa quantité la valeur. Suis une Map pendant un remplacement, une recherche infructueuse et un nettoyage. Examine ensuite pourquoi une clé personnalisée peut ne pas être trouvée même lorsque ses champs semblent corrects. Chaque recherche dépend de ce que Java considère comme une même clé.

  2. 2
    ExplicationCrée une association par clé

    Crée HashMap<String, Integer> stock = new HashMap<>();. String décrit les clés ; Integer décrit les valeurs. La Map utilise des types référence, donc int ne peut pas être l’argument de type des valeurs. Java effectue l’autoboxing d’un littéral comme 6 lorsque stock.put("folder", 6) le stocke. Le diamant à droite permet à Java de déduire les deux types.

  3. 3
    ExempleRemplace une quantité

    Exécute ces mises à jour dans l’ordre :

    stock.put("folder", 6);
    stock.put("clip", 11);
    Integer old = stock.put("folder", 8);
    

    Le dernier appel trouve la clé folder existante, stocke 8 et renvoie 6 dans old. Il y a toujours deux clés. Une Map enregistre la dernière valeur d’une clé ; elle n’additionne pas automatiquement les quantités et n’en conserve pas l’historique.

  4. 4
    DéfiLis sans insérer

    Quelles sont les valeurs de n et de stock.size() après cette lecture ? La Map contient toujours folder 8 et clip 11.

    int n = stock.getOrDefault("tape", 0);
    

    ---reveal---

    n vaut 0 et la taille reste 2. La valeur par défaut est un résultat pour une clé absente, pas une entrée insérée. Une lecture avec get("tape") renvoie à la place null, dont l’unboxing en int est impossible.

  5. 5
    ExplicationLis les deux éléments des paires ensemble

    Une boucle sur les entrées fournit chaque clé et sa valeur ensemble :

    for (Map.Entry<String, Integer> e : stock.entrySet()) {
        System.out.println(e.getKey() + ": " + e.getValue());
    }
    

    Importe java.util.Map. La boucle peut afficher les deux associations sans appel distinct à get. Si seule une somme est nécessaire, parcours stock.values() et additionne les quantités ; les quantités répétées contribuent chacune séparément.

  6. 6
    Point cléNe déduis pas quelle entrée vient en premier

    La sortie peut afficher folder avant clip ou clip avant folder. HashMap ne garantit aucun de ces ordres. Un résultat comme une somme n’est pas affecté, mais une règle qui conserve le premier score à égalité peut dépendre du parcours. Choisis LinkedHashMap pour l’ordre d’insertion ou TreeMap pour des clés triées, et prévois une règle explicite pour départager les maxima à égalité lorsque le gagnant doit être prévisible.

  7. 7
    ExempleSupprime pendant le parcours

    Supposons que folder vaille maintenant 0 et clip 11. Supprime les quantités nulles avec un itérateur :

    Iterator<Map.Entry<String, Integer>> it =
        stock.entrySet().iterator();
    while (it.hasNext()) {
        if (it.next().getValue() == 0) {
            it.remove();
        }
    }
    

    L’itérateur supprime son entrée courante et poursuit le parcours sans erreur. Appeler stock.remove pendant un parcours for-each peut au contraire déclencher ConcurrentModificationException.

  8. 8
    DéfiCrée une copie distincte des clés

    Avant le nettoyage, keys est créée avec new ArrayList<>(stock.keySet()). Si keys.remove("folder") est appelé, qu’arrive-t-il à la Map de stocks ?

    ---reveal---

    La Map conserve son association pour folder. keys est une liste distincte des clés qui existaient au moment de la copie. Une suppression directement dans stock.keySet() supprimerait l’entrée de la Map, car cet objet est une vue liée.

  9. 9
    ExempleEssaie une clé personnalisée

    Imagine que Bin possède les champs row et column et ne redéfinit pas les méthodes d’égalité. Stocke un libellé avec new Bin(3, 4), puis recherche-le avec un autre new Bin(3, 4). La recherche renvoie null. Ce sont deux objets différents et la méthode Object.equals héritée utilise l’identité. Les valeurs identiques des champs n’ont pas encore été intégrées à une règle de correspondance des clés.

  10. 10
    ExplicationRends l’égalité et le hachage cohérents

    Pour définir l’identité d’un casier selon ses coordonnées, redéfinis equals(Object other) afin de comparer la ligne et la colonne, et redéfinis hashCode() avec les mêmes champs, par exemple Objects.hash(row, column). Des coordonnées égales doivent produire des codes de hachage égaux. Un code de hachage identique ne suffit pas à établir l’égalité ; la vérification d’égalité distingue toujours des clés de coordonnées différentes.

  11. 11
    DéfiRepère une surcharge

    Une classe définit public boolean equals(Bin other) et un hashCode() fondé sur ses coordonnées. Pourquoi une recherche avec un casier distinct mais d’apparence égale peut-elle encore échouer ?

    ---reveal---

    Le paramètre doit être de type Object pour redéfinir la méthode d’égalité de Java. La méthode dont le paramètre est de type Bin est une surcharge et laisse en place l’égalité par identité héritée. Ajouter @Override à cette signature incorrecte permet au compilateur de révéler l’erreur.

  12. 12
    DéfiCorrige une conception qui modifie une clé

    Une clé représentant un casier utilise la ligne et la colonne dans ses méthodes d’égalité et de hachage. Le programme modifie sa ligne pendant qu’elle est stockée, puis ne retrouve plus son libellé. Comment doit-il mettre à jour l’emplacement, puis supprimer sans erreur les libellés vides pendant le parcours ?

    ---reveal---

    Supprime l’association avant de modifier la clé, puis réinsère-la. Pour le nettoyage pendant le parcours, utilise la méthode de suppression propre à l’itérateur des entrées. La stabilité de l’identité de la clé et la sûreté du parcours résolvent deux aspects différents de cette mise à jour.

  13. 13
    RécapitulatifGarde une liste de vérification pour les mises à jour de Map

    Pour une recherche infructueuse, décide si une valeur par défaut ou une vérification explicite de l’absence convient à la tâche. Pour une boucle, détermine si l’ordre compte et si des clés seront supprimées. Pour une clé personnalisée, vérifie la signature exacte de equals(Object), la concordance des champs utilisés pour le hachage et la stabilité de l’identité. Ces vérifications repèrent différentes causes d’un même symptôme : une association que le programme ne peut pas utiliser comme prévu.

2

Construis les informations de présence à l’arrivée des enregistrements

12 étapes
Compte les enregistrements, regroupe les membres distincts et maintiens la cohérence des index de recherche.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionTransforme les arrivées en réponses utiles
  2. 2
    ExempleCommence à compter les séances
  3. 3
    ExempleDistingue les séances distinctes des enregistrements
  4. 4
    DéfiCorrige un effectif remis à zéro
  5. 5
    ExplicationCrée un groupe une seule fois
  6. 6
    ExempleSuis la référence interne
  7. 7
    DéfiTrouve le bogue du groupe partagé
  8. 8
    ExplicationIndexe par une clé d’identification
  9. 9
    Point cléModifie un objet présent à plusieurs endroits
  10. 10
    DéfiMaintiens la cohérence lors d’une suppression
  11. 11
    DéfiCombine les effectifs et l’appartenance sans doublons
  12. 12
    RécapitulatifVérifie une première arrivée et une répétition
3

Compare deux groupes de participants

9 étapes
Utilise l’appartenance aux ensembles, préserve les originaux et indique la bonne différence.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionCherche qui est venu, pas le nombre de passages
  2. 2
    ExempleRéunis les pointages répétés
  3. 3
    DéfiArrête-toi à la première arrivée répétée
  4. 4
    ExempleNe conserve que les membres communs
  5. 5
    ExplicationChoisis le sens de la différence
  6. 6
    DéfiTeste un groupe sélectionné
  7. 7
    ConseilChoisis un ordre utile pour le compte rendu
  8. 8
    DéfiProduis un compte rendu trié des absences
  9. 9
    RécapitulatifConsidère l’ensemble receveur comme le groupe de départ
4

Lis les déclarations et les copies de collections

10 étapes
Utilise les interfaces, diagnostique les surcharges et distingue la structure des objets partagés.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionLis les deux côtés de la déclaration
  2. 2
    ExplicationDéclare ce dont l’appelant a besoin
  3. 3
    ExempleUtilise un paramètre plus général pour la lecture
  4. 4
    DéfiDiagnostique la méthode absente
  5. 5
    LienChoisis le sens du contenu
  6. 6
    ExempleSuis une suppression d’entier
  7. 7
    DéfiCopie avant de trier
  8. 8
    Point cléDistingue les modifications des objets de celles de la liste
  9. 9
    DéfiTransmets la bonne vue de la Map
  10. 10
    RécapitulatifVérifie le type, l’opération et l’objet
5

Construis un classement qui traite correctement les égalités

15 étapes
Trie des chaînes et des objets, écris des comparaisons sûres et vérifie l’appartenance à un ensemble trié.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionChoisis ce qui vient en premier
  2. 2
    ExempleTrie la même liste
  3. 3
    ExplicationExamine le premier caractère différent
  4. 4
    DéfiUtilise un ordre fourni
  5. 5
    ExplicationDonne un ordre naturel à une classe
  6. 6
    ExempleÉvite une fausse égalité numérique
  7. 7
    DéfiInverse l’ordre du champ numérique
  8. 8
    ExempleNe départage que les égalités réelles
  9. 9
    ExempleSuis le classement
  10. 10
    DéfiObserve ce que conserve un ensemble arborescent
  11. 11
    Point cléFais correspondre l’ordre à l’identité
  12. 12
    LienVérifie la clé d’une Map triée
  13. 13
    DéfiConserve tous les résultats dans une liste classée
  14. 14
    ConseilFais fonctionner la règle pour trois éléments
  15. 15
    RécapitulatifVérifie une comparaison dans deux situations
6

Choisis des structures pour une liste de cours

10 étapes
Adapte la recherche, l’appartenance, l’ordre et le coût sans multiplier les parcours.

Enregistre cette unité pour suivre chaque Leçon Interactive pas à pas.

  1. 1
    IntroductionÉnumère les questions que pose le programme
  2. 2
    ExempleRepère le parcours dans la boucle
  3. 3
    ExplicationPrépare une seule fois les tests d’appartenance
  4. 4
    DéfiCompare des entrées qui grandissent
  5. 5
    ExempleConserve les enregistrements d’inscription répétés
  6. 6
    ExplicationChoisis l’ordre externe et l’ordre interne
  7. 7
    DéfiCorrige une règle de doublons inadaptée
  8. 8
    ConseilTiens compte du coût de l’ordre nécessaire
  9. 9
    DéfiCombine les éléments de la conception finale
  10. 10
    RécapitulatifChoisis le comportement avant de mesurer la vitesse

HashMap et collections en Java : QCM

50 Questions Pratiques en 5 séries

Série 1 : Lis et mets à jour des Map de façon fiable10 Questions Pratiques

Question 1 sur 10

Une HashMap<String, Integer> vide reçoit put("brush", 5) puis put("brush", 14). Quelle est sa taille et quelle est la valeur associée à "brush" ?
  1. Taille 2 ; valeur 14.
  2. Taille 1 ; valeur 14.
  3. Taille 1 ; valeur 19.
  4. Taille 2 ; valeur 5.
Afficher la réponseMasquer la réponse
Réponse : B
Les deux mises à jour utilisent la même clé : la seconde remplace donc la première valeur et la Map conserve une entrée. La valeur est 14, pas 19 : put n’ajoute pas la quantité reçue à la quantité précédente. Une accumulation nécessite une expression qui lit puis met à jour la valeur.

Question 2 sur 10

Une Map de quantités non nulles ne contient pas la clé "tray". Que se passe-t-il à l’exécution de int n = map.get("tray"); ?
  1. Elle stocke 0 dans n et continue.
  2. Elle lève une ClassCastException.
  3. Elle insère "tray" avec la valeur 0.
  4. Elle lève une NullPointerException.
Afficher la réponseMasquer la réponse
Réponse : D
Un appel à get pour une clé absente renvoie null et l’affectation de ce résultat à un int tente d’en effectuer l’unboxing. Null n’a pas de valeur entière primitive, donc Java lève NullPointerException. La Map ne fournit pas zéro et ne crée pas de quantité simplement parce que la variable de destination est numérique.

Question 3 sur 10

Une boucle doit lire dans une Map chaque identifiant d’appareil avec son état. Quelle vue fournit les deux dans un même élément de la boucle ?
  1. entrySet()
  2. keySet()
  3. values()
  4. map.keySet().toArray()
Afficher la réponseMasquer la réponse
Réponse : A
entrySet() fournit une entrée contenant à la fois une clé et sa valeur associée. Une boucle sur les clés peut retrouver la valeur par une autre recherche, mais l’élément de l’ensemble des clés ne fournit que la clé. La vue des valeurs ne permet pas d’identifier la clé associée à chaque état.

Question 4 sur 10

Deux objets distincts sont égaux selon une méthode equals correcte. Que doivent valoir leurs codes de hachage ?
  1. Des valeurs entières différentes.
  2. Leurs nombres de champs respectifs.
  3. Une même valeur entière.
  4. Leurs adresses mémoire respectives.
Afficher la réponseMasquer la réponse
Réponse : C
Des objets égaux doivent renvoyer des codes de hachage égaux pour qu’une collection fondée sur le hachage puisse les retrouver selon la même règle de correspondance. Des codes de hachage différents pour des objets égaux violent ce contrat. La réciproque est fausse : deux objets différents peuvent partager un code de hachage.

Question 5 sur 10

Une Map contient "beam" → 9. Le programme exécute Integer old = map.put("beam", 13); puis Integer removed = map.remove("beam");. Que valent old, removed et la taille finale ?
  1. 13, 13 et 0.
  2. 9, 9 et 0.
  3. 9, 13 et 1.
  4. 9, 13 et 0.
Afficher la réponseMasquer la réponse
Réponse : D
Le remplacement renvoie l’ancienne valeur 9, tandis que l’entrée contient maintenant 13. La suppression renvoie donc 13 et supprime l’unique entrée, ce qui laisse une taille de 0. Considérer que le premier résultat est 13 revient à confondre la valeur renvoyée par put avec celle qu’il stocke.

Question 6 sur 10

Une boucle de nettoyage des stocks parcourt entrySet() et doit supprimer chaque entrée de valeur nulle. Comment doit-elle supprimer l’entrée pendant le parcours ?
  1. Utiliser l’itérateur du parcours et appeler son remove() après next().
  2. Utiliser une boucle for-each et appeler remove() sur la Map pour chaque clé de valeur nulle.
  3. Utiliser une boucle sur les entrées et remplacer chaque valeur nulle par null.
  4. Utiliser une boucle sur les valeurs et supprimer directement chaque clé de valeur nulle de keySet().
Afficher la réponseMasquer la réponse
Réponse : A
La méthode de suppression propre à l’itérateur coordonne la suppression avec sa position de parcours actuelle. Une suppression directe par la Map ou une vue liée modifie la structure pendant le parcours et peut déclencher ConcurrentModificationException. Remplacer une quantité par null ne supprimerait pas l’entrée.

Question 7 sur 10

Une classe Cell définit equals(Cell other) et un hashCode fondé sur ses champs. Des cellules distinctes dont les champs sont égaux ne correspondent pas comme clés de HashMap. Quelle modification de méthode corrige l’erreur d’égalité ?
  1. Conserver equals(Cell other) et renvoyer un code de hachage constant.
  2. Redéfinir equals(Object other) avec les mêmes comparaisons de champs.
  3. Remplacer la méthode d’égalité par un toString() fondé sur les champs.
  4. Ajouter compareTo(Cell other) sans modifier les méthodes d’égalité.
Afficher la réponseMasquer la réponse
Réponse : B
Une Map utilise equals(Object) : la méthode dont le paramètre est de type Cell est donc une surcharge et laisse en place l’égalité par identité héritée. Redéfinis la méthode dont le paramètre est de type Object et utilise des champs correspondants pour le hachage. Modifier uniquement le code de hachage ne peut pas faire intervenir la mauvaise méthode d’égalité dans la recherche.

Question 8 sur 10

Une recherche dans une HashMap enregistre une clé uniquement lorsque son score est strictement supérieur au meilleur score rencontré jusque-là. Deux clés partagent le score le plus élevé. Quel résultat le programme peut-il garantir ?
  1. L’une des clés à égalité, sans ordre de départage garanti.
  2. La clé à égalité insérée le plus tôt dans la Map.
  3. La clé à égalité dont le nom vient en premier par ordre alphabétique.
  4. La clé à égalité insérée le plus récemment dans la Map.
Afficher la réponseMasquer la réponse
Réponse : A
La recherche conserve la première clé à égalité qu’elle parcourt, car un score égal ne satisfait pas le test strictement supérieur. Une HashMap ne garantit ni l’ordre d’insertion ni l’ordre alphabétique pour le parcours. Un résultat prévisible en cas d’égalité nécessite une règle explicite de départage ou un ordre choisi à cette fin.

Question 9 sur 10

Une Map contient initialement "ink" → 4 et "paper" → 0. keys est une nouvelle ArrayList copiée à partir de son ensemble de clés. Le programme supprime "ink" de keys, supprime "paper" par la vue de l’ensemble des clés de la Map, puis double toutes les valeurs restantes de la Map. Que reste-t-il dans la Map ?
  1. Uniquement "paper" → 0.
  2. Aucune association.
  3. Uniquement "ink" → 8.
  4. Les deux associations "ink" → 8 et "paper" → 0.
Afficher la réponseMasquer la réponse
Réponse : C
La liste copiée est indépendante : y supprimer ink laisse donc son association intacte. La vue de l’ensemble des clés est liée à la Map : y supprimer paper efface donc cette association. Doubler la valeur restante de ink donne 8 ; traiter la liste copiée comme une autre vue liée conduirait à supprimer les deux entrées à tort.

Question 10 sur 10

L’égalité et le hachage de Location utilisent une coordonnée mutable. Une clé est stockée, puis sa coordonnée est modifiée pendant son stockage ; la recherche ne retrouve alors plus son association. Quelle séquence de mise à jour la conception doit-elle utiliser pour éviter cet échec ?
  1. Modifier la coordonnée ; rechercher avec la nouvelle coordonnée ; réinsérer.
  2. Supprimer avant la mutation ; modifier la coordonnée ; réinsérer.
  3. Modifier la coordonnée ; remplacer equals ; rechercher avec l’ancienne coordonnée.
  4. Garder une seconde référence ; modifier la coordonnée ; rechercher avec celle-ci.
Afficher la réponseMasquer la réponse
Réponse : B
La suppression doit avoir lieu tant que la clé possède encore l’identité d’égalité et de hachage utilisée lors de l’insertion. Le programme peut ensuite la modifier et la réinsérer sous sa nouvelle identité. Une recherche avec la même référence après mutation ne corrige pas le problème : le code de hachage modifié peut toujours mener ailleurs que vers l’entrée stockée.
Série 2 : Construis des effectifs et compare des groupes10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Une Map d’effectifs enregistre "north" → 4, "south" → 2 et "west" → 3. Combien de clés distinctes contient-elle ?
  1. 9
  2. 4
  3. 3
  4. 2
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une HashSet contient déjà "cedar". Que renvoie un nouvel appel à add("cedar") ?
  1. false
  2. true
  3. null
  4. La chaîne stockée.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Un cours doit énumérer chaque participant une seule fois, même lorsque des enregistrements d’inscription en double arrivent. Quelle règle de collection interne convient à chaque groupe de cours ?
  1. Une liste d’identifiants de participants.
  2. Un effectif entier des enregistrements.
  3. Un identifiant de participant sous forme de chaîne.
  4. Un ensemble d’identifiants de participants.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

La boucle traite "red", "gold", "red", "blue", "gold", "red" avec counts.put(word, counts.getOrDefault(word, 0) + 1). Quels sont l’effectif de red et la taille de la Map ?
  1. Effectif de red : 1 ; taille : 3.
  2. Effectif de red : 3 ; taille : 3.
  3. Effectif de red : 3 ; taille : 6.
  4. Effectif de red : 6 ; taille : 3.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Dans une boucle de regroupement, chaque arrivée exécute groups.put(team, new ArrayList<>()); puis groups.get(team).add(name);. Une équipe reçoit Omar, Pia, puis Ren. Que reste-t-il sous cette équipe ?
  1. [Omar, Pia, Ren]
  2. [Ren]
  3. [Omar]
  4. Une liste vide.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

A = {2, 5, 8, 11} et B = {5, 11, 14}. Un ensemble copié C contient initialement A, puis exécute C.removeAll(B). Que contient C ?
  1. {5, 11}
  2. {14}
  3. {2, 5, 8, 11, 14}
  4. {2, 8}
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Un même objet Device est stocké dans une liste et dans une Map par identifiant. Il est récupéré dans la Map, puis son champ d’état change. Quel état la référence stockée dans la liste expose-t-elle ?
  1. L’état modifié du même objet.
  2. L’état d’origine d’un objet copié distinct.
  3. Null jusqu’au remplacement de l’entrée de liste.
  4. L’état modifié après un second put dans la Map seulement.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

La séquence est [12, 7, 4, 12, 7]. Une boucle s’arrête au premier !seen.add(n). Quel nombre est indiqué ?
  1. 7
  2. 4
  3. 12
  4. Aucun nombre.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Une même ArrayList est stockée sous "Morning" et "Evening". Le programme ajoute "Lee" par Morning, puis remplace l’association de Evening par une nouvelle liste et ajoute "Jo" par Evening. Quels sont les groupes finaux ?
  1. Morning [Lee] ; Evening [Jo].
  2. Morning [Lee, Jo] ; Evening [Lee, Jo].
  3. Morning [] ; Evening [Lee, Jo].
  4. Morning [Jo] ; Evening [Jo].
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

A = {1, 3, 6} et B = {3, 6, 9}. C est copié à partir de A et exécute retainAll(B). D est copié à partir de B et exécute removeAll(C). Quels sont D et le résultat de A.containsAll(C) ?
  1. D = {1} ; le résultat est true.
  2. D = {9} ; le résultat est false.
  3. D = {3, 6, 9} ; le résultat est false.
  4. D = {9} ; le résultat est true.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 3 : Utilise les interfaces et trie des données10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Dans Set<String> codes = new HashSet<>();, quel est le type déclaré de codes ?
  1. HashSet<String>
  2. String
  3. Collection<HashSet>
  4. Set<String>
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Que signifie une valeur positive renvoyée par a.compareTo(b) ?
  1. a précède b dans cet ordre.
  2. a et b sont à égalité dans cet ordre.
  3. a suit b dans cet ordre.
  4. a possède un champ numérique plus grand.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une List<Integer> mutable contient initialement [4, 8, 12]. Elle exécute remove(1). Que reste-t-il ?
  1. [4, 12]
  2. [8, 12]
  3. [4, 8]
  4. [4, 8, 12]
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Quel est l’ordre naturel après tri des chaînes "zebra", "Apron", "18", "3", "ant" ?
  1. [« 3 », « 18 », « ant », « Apron », « zebra »]
  2. [« 18 », « 3 », « Apron », « ant », « zebra »]
  3. [« 18 », « 3 », « ant », « Apron », « zebra »]
  4. [« Apron », « ant », « zebra », « 18 », « 3 »]
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une méthode qui ne fait que lire accepte une Collection<String>. Un appelant possède Map<String, String> labels et veut que la méthode traite chaque valeur de notation. Que doit-il transmettre ?
  1. labels.values()
  2. labels
  3. labels.entrySet()
  4. labels.keySet().iterator()
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Une comparaison de prix renvoie (int) (this.price - other.price). Quel problème se produit pour les prix 6,8 et 6,3 ?
  1. Elle place toujours 6,8 avant 6,3.
  2. Elle dépasse l’intervalle des int.
  3. Elle renvoie zéro pour des prix différents.
  4. Elle transforme les deux prix stockés en entiers.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Les résultats doivent être triés par points décroissants, puis par nom de A à Z. La comparaison principale est non nulle. Que doit faire ensuite compareTo ?
  1. Comparer les noms et renvoyer le résultat.
  2. Renvoyer zéro pour conserver l’ordre d’entrée.
  3. Renvoyer l’opposé de la comparaison des noms.
  4. Renvoyer le résultat de la comparaison principale.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Une liste modifiable contient un objet Ticket mutable. Une seconde ArrayList est copiée à partir de cette liste. Le programme modifie le libellé du ticket par la copie, puis vide celle-ci. Que contient la liste d’origine ?
  1. Une liste vide qui ne contient plus de ticket.
  2. Le même ticket avec son libellé modifié.
  3. Un ticket distinct avec son libellé d’origine.
  4. Le même ticket avec son libellé d’origine.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Une classe compare selon le niveau décroissant, puis selon le code croissant. Les enregistrements sont Delta 2, Beta 4, Alpha 2 et Echo 4. Quel ordre obtient-on ?
  1. Echo 4, Beta 4, Delta 2, Alpha 2.
  2. Alpha 2, Beta 4, Delta 2, Echo 4.
  3. Beta 4, Echo 4, Alpha 2, Delta 2.
  4. Alpha 2, Delta 2, Beta 4, Echo 4.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Reading.equals utilise l’identifiant de station et la température, mais sa comparaison naturelle n’utilise que la température. Une TreeSet utilisée avec ses réglages par défaut reçoit A à 16, B à 16, puis C à 12. Quels sont sa taille et les identifiants conservés ?
  1. Taille 2 ; identifiants C et A.
  2. Taille 3 ; identifiants C, A et B.
  3. Taille 2 ; identifiants C et B.
  4. Taille 1 ; identifiant C uniquement.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 4 : Diagnostique le comportement des collections10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Un programme stocke les précipitations en millimètres dans une case pour chacun des douze mois. Il lui faut un nombre fixe de cases pour des valeurs numériques primitives. Quelle structure convient directement ?
  1. Un Set<Double> de mesures.
  2. Un tableau double[12].
  3. Une Map<Double, String> de mois.
  4. Une HashSet<Integer> de numéros de mois.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une HashMap contient la clé "pending" explicitement associée à null. Que renvoie getOrDefault("pending", 20) ?
  1. 20
  2. 0
  3. null
  4. Une exception lors de la recherche elle-même.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Que se passe-t-il lors de l’évaluation de Set.of("draft", "final", "draft") ?
  1. Elle lève IllegalArgumentException.
  2. Elle renvoie un ensemble de deux éléments.
  3. Elle renvoie une liste de trois éléments.
  4. Elle lève UnsupportedOperationException.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Un index de membres utilise les noms affichés comme clés. Deux membres différents nommés "Ari Chen" sont insérés et le premier ne peut plus être retrouvé par ce nom. Quelle conception conserve directement les deux pour une recherche individuelle ?
  1. Garder le nom comme clé, mais utiliser TreeMap.
  2. Garder le nom comme clé dans une LinkedHashMap.
  3. Appeler à nouveau put avec le même nom.
  4. Indexer chaque membre par son identifiant unique.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une liste mutable contient actuellement [10, 2, 7]. Quel est son contenu après Collections.reverse(list) ?
  1. [10, 7, 2]
  2. [2, 7, 10]
  3. [7, 10, 2]
  4. [7, 2, 10]
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un programme vérifie de façon répétée si des identifiants figurent dans une grande ArrayList et n’a pas besoin des positions pour ces vérifications. Quelle modification évite de répéter tout le travail de recherche ?
  1. Construire une nouvelle HashSet dans la boucle de recherche.
  2. Copier une fois l’ArrayList dans une LinkedList.
  3. Construire une HashSet avant la boucle de recherche.
  4. Trier une nouvelle ArrayList pour chaque recherche.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une Map de regroupement ne contient pas la clé "Support". Le programme évalue List<String> result = groups.getOrDefault("Support", new ArrayList<>()); puis ajoute "Nia" à result. Que renvoie un appel ultérieur à groups.get("Support") ?
  1. null, car la valeur par défaut n’a jamais été insérée.
  2. Une liste contenant Nia, car la valeur par défaut est devenue le groupe.
  3. Une liste vide, car la valeur par défaut a été stockée avant l’ajout.
  4. Une exception, car une liste par défaut non stockée ne peut pas être modifiée.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

L’égalité de ScoreKey utilise l’équipe et les points ; sa comparaison naturelle n’utilise que les points. Une TreeMap utilisée avec ses réglages par défaut reçoit la clé East-30 avec la valeur "old", West-30 avec la valeur "new", puis North-18 avec la valeur "low". Quelle est sa taille et quelle valeur retrouve-t-on avec East-30 ?
  1. Taille 3 ; la valeur est "old".
  2. Taille 2 ; la valeur est "new".
  3. Taille 2 ; la valeur est "old".
  4. Taille 1 ; la valeur est "low".
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

A = {4, 7, 10} et B = {7, 10, 13}. Une copie U exécute d’abord addAll(B), puis removeAll(A). Que vaut U et l’un des ensembles d’origine a-t-il changé ?
  1. U = {4} ; les deux ensembles d’origine sont inchangés.
  2. U = {4, 13} ; seul A est modifié.
  3. U = {7, 10} ; seul B est modifié.
  4. U = {13} ; les deux ensembles d’origine sont inchangés.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un compte rendu doit présenter les cours par ordre alphabétique et les identifiants distincts des membres de chaque cours dans l’ordre de leur première inscription. Quelles implémentations externe et interne conviennent ensemble ?
  1. TreeMap à l’extérieur ; LinkedHashSet à l’intérieur.
  2. LinkedHashMap à l’extérieur ; TreeSet à l’intérieur.
  3. TreeMap à l’extérieur ; ArrayList à l’intérieur.
  4. HashMap à l’extérieur ; LinkedHashSet à l’intérieur.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Série 5 : Combine recherche, regroupement et ordre10 Questions Pratiques

Enregistre cette unité pour voir chaque réponse et t'entraîner sur chaque série.

Question 1 sur 10

Qu’est-ce qui détermine l’égalité entre une ArrayList et une LinkedList contenant les mêmes valeurs d’éléments ?
  1. Les valeurs doivent apparaître dans le même ordre.
  2. Les listes doivent avoir la même classe concrète.
  3. Seul le nombre de valeurs distinctes doit correspondre.
  4. Les références aux éléments doivent toutes être identiques.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 2 sur 10

Une Map de sommes initialement vide traite réparations 4,25, livraison 2,50 et réparations 3,75 en utilisant une addition avec zéro comme valeur par défaut. Quelle est sa taille et quelle est la somme pour les réparations ?
  1. Taille 3 ; somme des réparations : 8,00.
  2. Taille 2 ; somme des réparations : 3,75.
  3. Taille 2 ; somme des réparations : 10,50.
  4. Taille 2 ; somme des réparations : 8,00.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 3 sur 10

Une classe personnalisée dont la méthode d’égalité est correcte renvoie le même code de hachage pour chaque instance. Quelles sont les conséquences sur la correction des résultats de HashSet et sur la vitesse des recherches ?
  1. Toutes les valeurs sont réunies en un élément, ce qui accélère les recherches.
  2. Les valeurs différentes restent valides, mais les recherches peuvent ralentir.
  3. Les valeurs distinctes restent valides, avec une recherche en temps constant garantie.
  4. Chaque insertion échoue à la compilation car les codes de hachage se répètent.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 4 sur 10

Une classe de température doit comparer deux champs double par ordre croissant sans fausses égalités dues à un transtypage. Quelle expression de retour convient ?
  1. (int) (this.value - other.value)
  2. Double.compare(other.value, this.value)
  3. Double.compare(this.value, other.value)
  4. Integer.compare((int) this.value, (int) other.value)
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 5 sur 10

Une Map contient deux clés différentes associées chacune à 6. Quel total obtient-on en additionnant map.values() ?
  1. 12
  2. 6
  3. 2
  4. 1
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 6 sur 10

Un catalogue conserve les mêmes objets Item dans un index par identifiant et dans un index associant chaque catégorie à une liste. La catégorie d’un article passe de Cables à Adapters. Modifier uniquement son champ de catégorie le laisse dans la liste Cables. Quelle mise à jour maintient la cohérence des index ?
  1. Le remplacer dans la Map par identifiant ; laisser les deux listes de catégories telles quelles.
  2. Remplacer la Map par identifiant par une TreeMap ; laisser les deux listes de catégories telles quelles.
  3. Déplacer sa référence entre les listes de catégories ; conserver son association par identifiant.
  4. Copier l’article sous l’ancienne catégorie ; supprimer son association par identifiant.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 7 sur 10

Une classe de joueur définit l’égalité par le nom et le score et compare d’abord le score décroissant, puis le nom croissant. Une TreeSet utilisée avec ses réglages par défaut reçoit Mira 9, Axel 12, Mira 9 et Bo 9 sous forme d’objets distincts. Quels membres contient-elle et dans quel ordre ?
  1. Axel 12, Mira 9, Bo 9.
  2. Axel 12, Mira 9, Mira 9, Bo 9.
  3. Bo 9, Mira 9, Axel 12.
  4. Axel 12, Bo 9, Mira 9.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 8 sur 10

Un programme possède une liste de valeurs autorisées et une liste de valeurs à rechercher. Les deux tailles doublent. Compare des recherches complètes répétées dans la liste à la construction d’une seule HashSet de valeurs autorisées suivie des recherches dans celle-ci, avec un hachage adapté. Comment le travail total augmente-t-il ?
  1. Les deux travaux totaux peuvent quadrupler car les deux entrées contiennent deux fois plus de valeurs.
  2. Le travail de recherche dans la liste peut quadrupler ; celui de construction et de recherche dans l’ensemble double approximativement.
  3. Le travail de recherche dans la liste double approximativement ; celui de construction et de recherche dans l’ensemble reste constant.
  4. Les deux travaux totaux restent constants car chacun utilise un appel de méthode par recherche.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 9 sur 10

Une Map regroupe des notes par projet. Deux projets doivent conserver des listes indépendantes, les notes répétées et l’ordre d’arrivée. Le code existant crée une ArrayList partagée, la place sous chaque nouvelle clé et ajoute les notes par get. Quelle correction complète respecte ces exigences ?
  1. Conserver l’ArrayList partagée, mais remplacer chaque get par getOrDefault avec cette même liste.
  2. Créer une nouvelle ArrayList pour chaque nouvelle clé, puis ajouter les notes par sa référence stockée.
  3. Créer une nouvelle HashSet pour chaque nouvelle clé, puis ajouter les notes par sa référence stockée.
  4. Créer une nouvelle ArrayList vide pour le projet à chaque arrivée, puis ajouter la note courante.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Question 10 sur 10

Un système documentaire nécessite des mots-clés distincts dans l’ordre de leur première apparition, une recherche directe d’objets par identifiant unique de document et un historique ordonné distinct qui conserve les visites répétées. Quelles structures répondent à ces trois besoins ?
  1. TreeSet pour les mots-clés ; List pour la recherche par identifiant ; HashSet pour l’historique.
  2. HashSet pour les mots-clés ; Map pour la recherche par identifiant ; TreeSet pour l’historique.
  3. LinkedHashSet pour les mots-clés ; Set pour la recherche par identifiant ; Map par identifiant de document pour l’historique.
  4. LinkedHashSet pour les mots-clés ; Map pour la recherche par identifiant ; List pour l’historique.
Afficher la réponseMasquer la réponse

Enregistre cette unité pour voir cette réponse.

Tu bloques sur ton propre exercice ? Aide aux Devoirs

Mots-Clés

70 Mots-Clés, chacun avec sa définition

A

Appartenance
L’appartenance indique si une valeur appartient à un ensemble ; contains la teste selon la règle de correspondance de cet ensemble.
Un programme de vérification des noms d’utilisateur teste l’appartenance avant d’accepter un nouveau nom dans son ensemble de noms déjà pris.
Autoboxing
L’autoboxing est la conversion automatique par Java d’une valeur primitive en l’objet enveloppe correspondant lorsqu’un objet est nécessaire.
Placer le littéral 12 dans une Map de valeurs Integer effectue automatiquement son autoboxing pour le stockage.

C

Choix d’une collection
Le choix d’une collection consiste à sélectionner une interface et une implémentation adaptées aux besoins de positions, de doublons, de recherche par clé et d’ordre.
Un compte rendu alphabétique d’effectifs et une liste de lecture ordonnée nécessitent des structures différentes car ils préservent des informations différentes.
Classe enveloppe
Une classe enveloppe fournit un type objet pour une valeur primitive, ce qui permet d’utiliser des nombres et d’autres données primitives comme arguments de type de collections.
Une Map de quantités utilise Integer comme type de valeur car int ne peut pas apparaître comme argument de type générique.
Clé mutable
Une clé mutable possède des données qui peuvent changer ; modifier les champs utilisés pour son égalité ou son code de hachage pendant son stockage peut empêcher sa recherche dans une Map.
Une clé de coordonnées est plus sûre avec des champs final qu’avec des mutateurs susceptibles de modifier son identité pendant son stockage.
Cohérence avec equals
La cohérence avec equals signifie que la comparaison renvoie zéro exactement lorsque l’égalité renvoie true : les deux règles identifient ainsi les mêmes valeurs.
Dans un ensemble arborescent, la comparaison des membres doit distinguer les mêmes identités que leur règle d’égalité.
Collection
Collection est l’interface Java commune aux groupes d’éléments ; elle est étendue par List et Set, mais reste distincte de l’interface Map.
Une méthode de comptage de mots qui ne fait que lire peut accepter une Collection<String> et parcourir une liste ou un ensemble.
Collection imbriquée
Une collection imbriquée stocke des collections à l’intérieur d’une autre structure, permettant aux clés externes et aux membres internes de suivre des règles distinctes.
Une Map de cours triée peut contenir des listes d’étudiants dans l’ordre d’insertion sans trier les étudiants eux-mêmes.
Collection non modifiable
Une collection non modifiable rejette les modifications structurelles ou les remplacements par son interface de programmation, mais les objets qu’elle contient peuvent rester mutables.
Une liste issue de List.of doit être copiée avant d’être triée, mais un objet mutable stocké n’est pas figé par cette liste.
Comparable
Comparable est l’interface Java par laquelle une classe définit son ordre naturel en implémentant une méthode compareTo typée.
Une classe de membre peut implémenter Comparable<Member> pour que le tri de listes puisse ordonner ses instances par taille.
Comparateur
Un comparateur est un objet qui fournit une règle de comparaison pouvant différer de l’ordre naturel d’une classe, comme l’ordre inverse ou un ordre insensible à la casse.
String.CASE_INSENSITIVE_ORDER trie une liste sans modifier la casse stockée dans chaque chaîne.
compareTo
La méthode compareTo renvoie un entier négatif, zéro ou un entier positif pour placer cet objet respectivement avant, au même rang que ou après un autre.
Un résultat de -8 place l’objet de gauche avant celui de droite, tout comme le ferait un résultat de -1.
Contrat de hachage
Le contrat de hachage exige que des objets égaux selon equals renvoient des codes de hachage égaux, tout en autorisant les collisions entre objets différents.
Les clés de coordonnées utilisent les mêmes champs x et y dans leur test d’égalité et dans leur méthode de calcul du code de hachage.
Copie superficielle
Une copie superficielle crée une structure de collection distincte contenant les mêmes références aux éléments au lieu de dupliquer les objets stockés.
Supprimer un livre d’une liste copiée laisse la liste source intacte, mais les deux listes peuvent toujours faire référence au même livre.
Coût de mise en place
Un coût de mise en place est le travail nécessaire pour construire une structure auxiliaire avant que les opérations ultérieures puissent profiter de son utilisation.
Un ensemble destiné aux tests d’appartenance doit être construit une fois avant de nombreuses vérifications, en incluant sa construction dans le travail total.
Critère de départage
Un critère de départage est une comparaison secondaire utilisée uniquement lorsque les champs comparés précédemment sont à égalité, ce qui préserve leur priorité dans l’ordre global.
Une comparaison de films par année puis par titre ne consulte les titres que pour les films sortis la même année.

D

Dépassement de capacité d’un entier
Un dépassement de capacité d’un entier se produit lorsqu’un résultat arithmétique dépasse l’intervalle du type int et que sa valeur est ramenée dans cet intervalle, ce qui peut donner le mauvais signe aux comparaisons par soustraction.
Comparer des champs int extrêmes avec Integer.compare évite l’inversion de signe que la soustraction peut provoquer.
Différence d’ensembles
Une différence d’ensembles contient les éléments du premier ensemble qui sont absents du second : inverser les ensembles peut donc changer le résultat.
Supprimer les participants du mardi d’une copie de l’ensemble du lundi permet de trouver ceux présents uniquement lundi, pas ceux présents uniquement mardi.

É

Égalité de contenu
L’égalité de contenu considère des objets distincts comme égaux lorsque leurs données choisies correspondent, grâce à une redéfinition appropriée de equals(Object).
Deux clés de coordonnées créées séparément peuvent retrouver la même notation lorsque leur méthode d’égalité compare les deux coordonnées.
Égalité par identité
L’égalité par identité ne considère des objets comme égaux que s’ils sont la même instance ; c’est l’égalité héritée de Object.
Sans redéfinition, un point nouvellement construit ne correspond pas à un point stocké de coordonnées identiques.
Élément distinct
Un élément distinct est une valeur considérée comme différente selon la règle de correspondance de la collection, quel que soit le nombre de ses occurrences.
Une Map d’effectifs pour "sun rain sun" contient deux clés de mots distincts, mais enregistre trois occurrences.

E

Encapsulation
L’encapsulation conserve les données dans une classe et expose des méthodes contrôlées, afin que la classe puisse maintenir des règles de mise à jour et de recherche.
Une classe de bibliothèque peut garder ses index privés pour que sa méthode addBook les mette à jour ensemble au lieu de laisser les appelants les modifier.
Ensemble
Un ensemble est une collection d’éléments distincts qui fournit des opérations d’appartenance sans les positions accessibles par indice d’une liste.
Un ensemble de villes visitées conserve une entrée par ville, même lorsqu’un voyageur y retourne plusieurs fois.

G

getOrDefault
La méthode getOrDefault renvoie la valeur associée à une clé ou la valeur par défaut fournie lorsqu’aucune association n’existe pour cette clé.
Lire un effectif absent avec zéro comme valeur par défaut donne 0 sans créer de nouvelle entrée dans la Map d’effectifs.

H

HashMap
Une HashMap est une Map Java modifiable qui stocke des clés uniques avec leurs valeurs associées et ne garantit aucun ordre de parcours particulier.
Une HashMap<String, Integer> peut rechercher la quantité actuelle d’un produit sans utiliser une position dans une liste.
HashSet
Une HashSet est un ensemble Java modifiable dont les opérations de base sont en temps constant en moyenne avec un hachage adapté et dont l’ordre de parcours n’est pas garanti.
Une HashSet<String> peut suivre les noms déjà traités pendant qu’un programme lit une séquence d’entrée plus longue.

I

Identifiant unique
Un identifiant unique distingue chaque objet dans les données indexées et empêche des enregistrements distincts de se disputer la même clé de Map.
Un identifiant de membre conserve deux personnes ayant le même nom affiché dans des entrées distinctes d’un index de membres.
Implémentation
Une implémentation est une classe concrète qui fournit les opérations d’une interface et détermine le comportement de l’objet créé.
HashMap et TreeMap implémentent toutes deux Map, mais garantissent des choses différentes concernant l’ordre des clés.
Index
Un index est une Map qui associe une clé d’identification à un objet, permettant de le rechercher par cette clé sans parcourir sans cesse une liste d’objets.
L’index par ISBN d’une bibliothèque peut renvoyer le même objet livre que celui qui figure aussi dans sa liste de tous les livres.
Interface
Une interface déclare des opérations que les classes qui l’implémentent fournissent, ce qui permet à une variable ou à un paramètre d’indiquer les capacités nécessaires.
Une méthode qui accepte List<String> peut recevoir une ArrayList ou une LinkedList sans changer sa signature.
Intersection
L’intersection de deux ensembles ne contient que les éléments qu’ils partagent ; retainAll supprime les valeurs non partagées de son ensemble receveur.
Ne conserver que les noms du mardi dans une copie de l’ensemble du lundi permet de trouver les personnes présentes les deux jours.
Itérateur
Un itérateur suit un parcours dans une collection et fournit des méthodes pour vérifier l’existence d’un élément suivant et le récupérer.
Une boucle de nettoyage des stocks utilise hasNext(), next() et le remove() de l’itérateur pour supprimer les quantités nulles.

L

LinkedHashMap
Une LinkedHashMap est une Map dont la forme ordinaire, fondée sur l’ordre d’insertion, parcourt les clés dans cet ordre tout en conservant les opérations habituelles d’une Map.
Remplacer un prix stocké conserve la place du produit dans une LinkedHashMap qui suit l’ordre d’insertion.
LinkedHashSet
Une LinkedHashSet stocke des éléments distincts tout en préservant leur ordre d’insertion, notamment l’ordre des premières occurrences lors d’une copie depuis une liste.
Une liste de mots-clés copiée dans une LinkedHashSet perd ses répétitions tout en conservant l’ordre de première apparition des mots-clés.
List
Une List stocke des éléments dans une séquence accessible par indice à partir de zéro, autorise les doublons et compare l’égalité selon l’ordre complet des éléments.
Une liste de lecture utilise les positions d’une liste pour conserver deux occurrences d’un même morceau à différents endroits de la séquence.
Listes parallèles
Des listes parallèles stockent des champs associés à des indices correspondants dans des listes distinctes : leur relation dépend donc de modifications structurelles coordonnées.
Supprimer le nom d’une personne sans supprimer le numéro au même indice décale les associations suivantes de l’annuaire.

M

Map
Une Map associe des clés uniques à des valeurs ; les valeurs peuvent se répéter, mais chaque clé possède au plus une valeur associée à un instant donné.
Deux produits peuvent être associés au prix 3,50 sans enfreindre l’exigence d’unicité de leurs clés.
Map.Entry
Une Map.Entry représente une association clé–valeur et donne accès à sa clé et à sa valeur ensemble pendant le parcours d’une Map.
Une boucle sur les entrées peut afficher le nom et le score d’un joueur sans rechercher à nouveau le score par son nom.
Modification structurelle
Une modification structurelle change l’ensemble des clés d’une Map, par exemple lorsqu’une nouvelle association est ajoutée ou qu’une association existante est supprimée.
Remplacer la quantité associée à une clé déjà présente modifie sa valeur sans modifier la structure de la Map.

N

Normalisation des clés
La normalisation des clés applique une règle de nettoyage cohérente avant le stockage et la recherche afin que des formes d’entrée équivalentes utilisent la même clé de Map.
Un programme de comptage de mots peut mettre les jetons en minuscules et supprimer la ponctuation avant d’ajouter chaque occurrence à sa Map.

O

Occurrence en double
Une occurrence en double est une occurrence en entrée dont une valeur égale a déjà été rencontrée ; un ensemble de valeurs déjà vues la détecte lorsque add renvoie false.
Dans la séquence 6, 9, 2, 9, 6, le second 9 est la première arrivée qui répète une valeur précédente.
Ordre de parcours
L’ordre de parcours est la séquence dans laquelle un parcours visite les éléments ou les entrées ; certaines implémentations en garantissent un et d’autres non.
Une recherche de score maximal nécessite une règle explicite de départage si son résultat doit être indépendant du parcours d’une HashMap.
Ordre des caractères
L’ordre des caractères compare les chaînes à leur première unité de code UTF-16 différente ; lorsqu’une chaîne est le début d’une autre, la plus courte vient en premier.
Dans les exemples "7", "Bee" et "ant", l’ordre naturel des chaînes place le chiffre avant les lettres.
Ordre naturel
Un ordre naturel est la comparaison par défaut fournie par une classe, comme l’ordre numérique croissant ou l’ordre des chaînes fondé sur les caractères.
Trier les chaînes "20" et "3" place "20" en premier car les caractères initiaux déterminent leur ordre.

P

Paire clé–valeur
Une paire clé–valeur relie une clé d’identification à une valeur associée dans une Map, comme un code produit associé à une quantité.
Dans une Map de stocks, la paire "pen" → 18 associe un nom de produit au nombre actuellement disponible.
Paramètre de type interface
Un paramètre de type interface accepte des objets par l’intermédiaire des opérations garanties par une interface, au lieu d’exiger une implémentation concrète particulière.
Une méthode de compte rendu peut accepter Map<String, Integer> tandis que les appelants choisissent un stockage fondé sur le hachage ou sur un arbre.
putIfAbsent
La méthode putIfAbsent stocke une valeur lorsqu’une clé ne possède aucune association non nulle ; sinon, elle conserve la valeur déjà associée à cette clé.
Avant d’ajouter un élément à un groupe, putIfAbsent peut garantir que sa clé possède une liste sans remplacer une liste existante.

R

Recherche par clé
Une recherche par clé trouve une valeur à l’aide d’un identifiant distinct, ce qui rend une Map utile lorsque des recherches répétées exigeraient autrement d’examiner les champs des objets.
Une Map par code produit répond directement aux demandes de prix, tandis qu’une liste nécessiterait une recherche du code correspondant.
Référence partagée
Une référence partagée permet à deux variables ou entrées d’accéder au même objet, de sorte qu’une modification de cet objet soit visible par l’une ou l’autre référence.
Deux clés de cours associées à un même objet liste affichent toutes deux un étudiant ajouté par une seule de ces clés.
Regroupement
Le regroupement réunit des éléments ayant une propriété commune sous une même clé de Map, en utilisant une liste ou un ensemble comme valeur pour stocker chaque groupe.
Une clé de cours peut mener à une liste d’étudiants, tandis qu’une clé de première lettre peut mener aux mots correspondants.

S

Somme cumulée
Une somme cumulée est un montant accumulé qui est mis à jour en ajoutant chaque nouvelle contribution au montant déjà stocké.
Une Map de dépenses lit l’ancienne somme d’une catégorie, ajoute le montant suivant et stocke le résultat augmenté.
Sous-ensemble
Un sous-ensemble a tous ses éléments dans un autre ensemble, qui peut contenir des éléments supplémentaires ; a.containsAll(b) vérifie si b est inclus dans a.
Un groupe sélectionné est un sous-ensemble d’un ensemble de participants lorsque chaque personne sélectionnée figure sur la liste de cet événement.
Surcharge
Une surcharge est une méthode qui porte le même nom qu’une autre, mais utilise des paramètres différents, permettant à Java de choisir une autre opération.
Pour une liste d’entiers, remove(1) sélectionne la suppression par indice, tandis que remove(Integer.valueOf(1)) sélectionne la suppression par valeur.
Syntaxe du diamant
La syntaxe du diamant utilise des chevrons vides lors de l’appel d’un constructeur pour que Java puisse déduire ses arguments de type à partir de la déclaration environnante.
Dans HashMap<String, Integer> m = new HashMap<>();, le diamant évite de répéter les deux types.

T

Table de correspondance
Une table de correspondance associe des codes ou des noms à des données qu’un programme récupère pour accomplir une autre tâche.
Un programme de calcul de commande lit les prix des produits dans une table avant d’ajouter la contribution de chaque produit.
Tableau
Un tableau stocke un nombre fixe d’éléments d’un même type, accessibles par indice, et peut contenir directement des valeurs primitives sans argument de type enveloppe.
Un double[12] peut fournir à chaque mois une case pour sa mesure de précipitations en millimètres.
Tableau des effectifs
Un tableau des effectifs associe chaque élément distinct à son nombre d’occurrences, en utilisant couramment les clés d’une Map pour les éléments et des valeurs entières pour les effectifs.
Une Map de comptage des mots distingue le nombre de mots différents du nombre total d’occurrences de mots.
Temps constant
Un temps constant décrit un travail qui reste approximativement indépendant du nombre d’éléments ; les opérations de base fondées sur le hachage ont ce coût en moyenne avec un hachage adapté.
Lire une position d’ArrayList ne nécessite pas de parcourir toutes les positions précédentes de cette liste.
Temps linéaire
Un temps linéaire décrit un travail qui peut augmenter proportionnellement au nombre d’éléments, comme lorsqu’une recherche peut examiner toute la collection.
Des tests d’appartenance répétés dans une longue liste peuvent nécessiter de parcourir à plusieurs reprises les mêmes noms stockés.
Temps logarithmique
Un temps logarithmique décrit un travail qui augmente lentement avec le nombre d’éléments, comme le coût garanti des recherches de base dans les Map et ensembles arborescents.
Une Map arborescente garde les clés triées tout en évitant un parcours complet pour chaque recherche ordinaire par clé.
Transitivité
La transitivité exige qu’un ordre place a avant c chaque fois qu’il place a avant b et b avant c, afin que les comparaisons restent cohérentes.
Comparer les champs selon un ordre de priorité fixe évite un cycle dans lequel chacun de trois objets en précède un autre.
TreeMap
Une TreeMap conserve les associations ordonnées par leurs clés et utilise la comparaison des clés pour identifier une association existante lors d’une recherche ou d’un remplacement.
Un compte rendu alphabétique des effectifs de mots peut utiliser une Map arborescente dont la plus petite clé est accessible par firstKey().
TreeSet
Une TreeSet garde les éléments triés et utilise son résultat de comparaison pour déterminer si un élément est déjà présent dans l’ensemble.
Une comparaison de membres fondée uniquement sur la taille fait occuper une seule position d’ensemble à deux membres différents de même taille.
Tri en place
Un tri en place réorganise la liste fournie elle-même au lieu de renvoyer une liste triée distincte à affecter par l’appelant.
Après Collections.sort(values), la variable de liste existante donne accès à ses éléments dans leur nouvel ordre.
Tri stable
Un tri stable préserve l’ordre relatif d’entrée des éléments considérés comme égaux selon la comparaison utilisée pour ce tri.
Deux joueurs à égalité selon une comparaison fondée uniquement sur le score conservent leur ordre relatif antérieur après un tri stable de liste.
Troncature
La troncature élimine la partie fractionnaire d’une valeur lors de son transtypage en int, ce qui peut transformer une petite différence non nulle en zéro lors d’une comparaison.
Transtyper en int la différence entre les prix 2,7 et 2,2 donne une fausse égalité au lieu d’un résultat de comparaison positif.
Type déclaré
Le type déclaré d’une variable détermine les méthodes que le compilateur autorise à appeler par cette variable, même si son objet possède des méthodes supplémentaires.
Une ArrayList stockée dans une variable List ne peut pas exposer ensureCapacity par cette variable.

U

Unboxing
L’unboxing est la conversion automatique par Java d’un objet enveloppe en valeur primitive ; le tenter avec null lève une exception.
Affecter à un int le résultat d’une recherche infructueuse de valeur Integer échoue car l’unboxing du null renvoyé est impossible.
Union
L’union de deux ensembles contient chaque élément présent dans l’un ou l’autre ensemble ; la méthode Java addAll la forme en modifiant l’ensemble receveur.
Copier l’ensemble des participants du lundi et y ajouter ceux du mardi donne toutes les personnes venues au moins un des deux jours.

V

Vue de collection
Une vue de collection expose une partie d’une autre structure par une interface de collection ; les modifications sont liées à la structure sous-jacente.
Supprimer un produit par l’ensemble des clés de la Map de stocks supprime l’entrée correspondante de la Map elle-même.

À propos de cette unité

Par StudeliSignaler une erreur

Crée ton propre Matériel d'Étude

Transforme tes notes, diapos et documents en Guides d'Étude, Questions Pratiques, Flashcards et 6 autres outils.

Commencer