Le quartierJV JavaPièce 6/7Avancé

Collections, génériques et exceptions

Manipuler des List et des Map, écrire du code générique, gérer les erreurs avec les exceptions et modéliser des cas avec sealed et switch.

Ce que tu vas apprendre

  • Utiliser List et Map à la place des tableaux.
  • Comprendre les génériques et la notation List<String>.
  • Gérer les erreurs avec try, catch et modéliser des cas avec sealed.

List : une liste qui grandit

Une collection est un objet qui range d'autres objets et dont la taille peut varier. La plus courante est la List.

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

List<String> courses = new ArrayList<>();
courses.add("farine");
courses.add("lait");
courses.remove("lait");

System.out.println(courses.size()); // 1
System.out.println(courses.get(0)); // farine

List est l'interface, ArrayList la classe qui l'implémente. On déclare le type avec l'interface et on crée avec la classe : le reste du code ne dépend pas du choix.

Pour une liste fixe, List.of("a", "b") crée une liste non modifiable : un add lève alors une exception.

Map : des paires clé et valeur

Une Map associe une clé à une valeur, comme un index.

import java.util.HashMap;
import java.util.Map;

Map<String, Integer> duree = new HashMap<>();
duree.put("Crêpes", 20);
duree.put("Cassoulet", 180);

System.out.println(duree.get("Crêpes"));              // 20
System.out.println(duree.getOrDefault("Pizza", 0));   // 0

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

Une clé est unique : un second put avec la même clé remplace la valeur. get d'une clé absente renvoie null, d'où l'intérêt de getOrDefault. HashMap ne garantit aucun ordre de parcours.

BesoinChoix
Suite ordonnée, accès par positionList
Éléments sans doublonSet
Accès par cléMap

Les génériques

Les chevrons de List<String> sont des génériques : ils indiquent le type des éléments. Le compilateur refuse alors d'ajouter un nombre dans une List<String>.

Tu peux écrire tes propres types génériques. T est un paramètre de type, remplacé à l'usage :

public record Paire<T>(T premier, T second) { }

Paire<String> duo = new Paire<>("sel", "poivre");
Paire<Integer> nombres = new Paire<>(1, 2);

La même classe sert pour des textes comme pour des nombres, avec la sécurité du typage. Un type générique ne s'utilise qu'avec des objets : on écrit List<Integer> et non List<int>.

Les exceptions

Une exception est un objet qui signale une erreur et interrompt le déroulement normal du programme. Sans traitement, elle arrête tout.

String texte = "vingt";

try {
    int minutes = Integer.parseInt(texte);
    System.out.println(minutes);
} catch (NumberFormatException e) {
    System.out.println("Durée invalide : " + texte);
} finally {
    System.out.println("Terminé");
}

Le fonctionnement :

  1. Le bloc try s'exécute. Dès qu'une exception se produit, il s'arrête.
  2. Le bloc catch correspondant au type de l'exception prend le relais.
  3. Le bloc finally, facultatif, s'exécute dans tous les cas.

Attrape le type le plus précis possible. Un catch (Exception e) qui ne fait rien cache les vrais problèmes.

Lancer et déclarer une exception

Pour signaler une erreur, utilise throw. Une exception « contrôlée » doit aussi être déclarée avec throws :

static void verifier(int portions) {
    if (portions <= 0) {
        throw new IllegalArgumentException("portions doit être positif");
    }
}

Java distingue deux familles. Les exceptions non contrôlées (comme IllegalArgumentException) héritent de RuntimeException : le compilateur n'impose rien. Les exceptions contrôlées (comme IOException, lors de la lecture d'un fichier) doivent être traitées par catch ou déclarées avec throws.

Ne renvoie jamais null pour signaler une erreur sans le documenter. Le premier appel à une méthode sur ce null lève une NullPointerException. Une exception claire, ou un Optional, vaut mieux.

sealed et switch par motif

Une interface sealed liste exactement ses implémentations. Avec des records, le switch peut tester le type de chaque cas :

sealed interface Resultat permits Succes, Echec { }
record Succes(String recette) implements Resultat { }
record Echec(String message) implements Resultat { }

static String afficher(Resultat r) {
    return switch (r) {
        case Succes s -> "Trouvée : " + s.recette();
        case Echec e -> "Erreur : " + e.message();
    };
}

Comme tous les cas possibles sont listés, aucun default n'est requis. Si tu ajoutes un nouveau type à permits, le compilateur signale chaque switch à compléter.

Pour continuer, explore les flux avec stream() sur une List et la classe Optional. Elles complètent naturellement ce cours.

À retenir

  • List garde un ordre et peut grandir ; Map associe des clés uniques à des valeurs.
  • Les chevrons, comme List<String>, fixent le type des éléments : le compilateur vérifie à ta place.
  • Un paramètre de type T permet d'écrire une classe valable pour plusieurs types.
  • try, catch et finally traitent une exception ; throw en déclenche une.
  • sealed avec des records et un switch donne un code exhaustif, vérifié par le compilateur.

Pour aller plus loin

Sources officielles

Ensuite

Projet
Lignes de code
Niveau
Le quartier
Appartement
Java
Pièce
6/7
Plan n°
java/06.collections-generiques-exceptions
Lignes de code · fiches rédigées à partir des documentations officielles, sources citées en bas de chaque page.