Menu
Coddy logo textTech

Erreurs Checked vs Unchecked

Fait partie de la section Programmation Orientée Objet du Journey Java de Coddy — leçon 61 sur 87.

Vous avez vu que la hiérarchie des exceptions de Java se divise en différentes branches. La distinction clé que vous devez comprendre est celle entre les exceptions checked (vérifiées) et unchecked (non vérifiées) — cela affecte la façon dont vous devez les gérer dans votre code.

Les exceptions contrôlées sont des exceptions que le compilateur vous oblige à gérer. Elles héritent directement de Exception (et non de RuntimeException). Vous devez soit les intercepter, soit les déclarer avec throws :

// Doit gérer IOException - c'est une exception vérifiée
public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);  // Peut lever une IOException
}

// Ou l'intercepter
public void readFileSafe(String path) {
    try {
        FileReader reader = new FileReader(path);
    } catch (IOException e) {
        System.out.println("File error: " + e.getMessage());
    }
}

Les exceptions non contrôlées étendent RuntimeException. Le compilateur ne vous oblige pas à les gérer — elles indiquent généralement des erreurs de programmation telles que des références nulles ou des accès de tableau invalides :

// Aucune déclaration throws n'est nécessaire
public int divide(int a, int b) {
    return a / b;  // Peut lever une ArithmeticException (non vérifiée)
}

String name = null;
name.length();  // NullPointerException (non vérifiée)

Lors de la création d'exceptions personnalisées, choisissez la classe parente en fonction de la manière dont vous souhaitez que les appelants les gèrent. Utilisez des exceptions contrôlées (checked exceptions) pour les conditions récupérables que l'appelant doit anticiper. Utilisez des exceptions non contrôlées (unchecked exceptions) pour les erreurs de programmation qui ne devraient pas se produire dans un code correct.

challenge icon

Défi

Facile

Construisons un système de vérification d'âge qui démontre la différence clé entre les exceptions vérifiées (checked) et non vérifiées (unchecked) ! Vous allez créer des exceptions personnalisées des deux types et voir comment le compilateur les traite différemment.

Vous organiserez votre code sur quatre fichiers :

  • InvalidAgeException.java : Créez une exception vérifiée pour les échecs de validation d'âge. Cette exception doit étendre directement Exception, ce qui signifie que les appelants seront obligés de la gérer. Incluez un constructeur qui accepte un message et le transmet à la classe parente.
  • NegativeAgeException.java : Créez une exception non vérifiée pour les cas où quelqu'un fournit un âge négatif (une erreur de programmation qui ne devrait pas se produire avec une entrée correcte). Celle-ci doit étendre RuntimeException. Incluez un constructeur qui accepte et transmet un message au parent.
  • AgeVerifier.java : Créez une classe qui valide les âges en utilisant les deux types d'exceptions. Incluez deux méthodes statiques :

    verifyAge(int age) - Cette méthode doit lever une NegativeAgeException (non vérifiée) avec le message "Age cannot be negative: " + age si l'âge est inférieur à 0. Si l'âge est inférieur à 18, levez une InvalidAgeException (vérifiée) avec le message "Must be 18 or older: " + age. Sinon, affichez "Age " + age + " verified successfully". Comme cette méthode lève une exception vérifiée, vous devez la déclarer avec throws InvalidAgeException.

    verifyAgeUncheckedOnly(int age) - Cette méthode utilise uniquement des exceptions non vérifiées. Si l'âge est négatif, levez une NegativeAgeException avec le même format de message. Si l'âge est inférieur à 18, levez une IllegalArgumentException avec le message "Too young: " + age. Sinon, affichez "Age " + age + " verified (unchecked method)". Remarquez que cette méthode n'a pas besoin de déclaration throws !

  • Main.java : Rassemblez votre système de vérification ! Vous recevrez une entrée : un âge (entier).

    Tout d'abord, affichez "=== Checked Exception Method ===" et appelez verifyAge avec l'âge saisi. Comme elle lève une exception vérifiée, vous devez l'envelopper dans un bloc try-catch. Interceptez InvalidAgeException et affichez "Checked exception caught: " + e.getMessage(). Interceptez également NegativeAgeException et affichez "Unchecked exception caught: " + e.getMessage().

    Ensuite, affichez une ligne vide et "=== Unchecked Exception Method ===". Appelez verifyAgeUncheckedOnly avec le même âge. Même si cette méthode peut lever des exceptions, vous n'êtes pas obligé de les intercepter. Cependant, enveloppez-la quand même dans un bloc try-catch pour gérer les erreurs proprement. Interceptez NegativeAgeException et affichez "Runtime exception caught: " + e.getMessage(). Interceptez IllegalArgumentException et affichez "Illegal argument caught: " + e.getMessage().

Vous recevrez une entrée : un entier représentant l'âge à vérifier.

Remarquez la différence clé : la méthode avec l'exception vérifiée nécessite une déclaration throws et oblige les appelants à la gérer, tandis que la méthode non vérifiée compile parfaitement sans aucune gestion d'exception. C'est la distinction fondamentale entre les exceptions vérifiées et non vérifiées en Java !

Aide-mémoire

Les exceptions Java sont divisées en exceptions vérifiées (checked) et non vérifiées (unchecked), ce qui détermine la manière dont le compilateur impose leur gestion.

Les exceptions vérifiées étendent directement Exception (pas via RuntimeException). Le compilateur vous oblige soit à les intercepter, soit à les déclarer avec throws :

// Doit être déclaré avec throws
public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);
}

// Ou l'intercepter
public void readFileSafe(String path) {
    try {
        FileReader reader = new FileReader(path);
    } catch (IOException e) {
        System.out.println("File error: " + e.getMessage());
    }
}

Les exceptions non vérifiées étendent RuntimeException. Le compilateur ne vous oblige pas à les gérer. Elles indiquent généralement des erreurs de programmation :

// Aucune déclaration throws n'est nécessaire
public int divide(int a, int b) {
    return a / b;  // Peut lever une ArithmeticException (non vérifiée)
}

String name = null;
name.length();  // NullPointerException (non vérifiée)

Lors de la création d'exceptions personnalisées, choisissez la classe parente en fonction de la manière dont les appelants doivent les gérer :

  • Utilisez des exceptions vérifiées (étendez Exception) pour les conditions récupérables que l'appelant doit anticiper
  • Utilisez des exceptions non vérifiées (étendez RuntimeException) pour les erreurs de programmation qui ne devraient pas se produire dans un code correct

Essayez vous-même

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int age = scanner.nextInt();
        
        // TODO: Tester la méthode d'exception vérifiée (checked exception)
        // Afficher : "=== Checked Exception Method ==="
        // Appeler AgeVerifier.verifyAge(age) dans un bloc try-catch
        // - Intercepter InvalidAgeException : afficher "Checked exception caught: [message]"
        // - Intercepter NegativeAgeException : afficher "Unchecked exception caught: [message]"
        
        
        // TODO: Afficher une ligne vide, puis "=== Unchecked Exception Method ==="
        // Appeler AgeVerifier.verifyAgeUncheckedOnly(age) dans un bloc try-catch
        // - Intercepter NegativeAgeException : afficher "Runtime exception caught: [message]"
        // - Intercepter IllegalArgumentException : afficher "Illegal argument caught: [message]"
        
    }
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet