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.
Défi
FacileConstruisons 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 directementException, 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 étendreRuntimeException. 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 uneNegativeAgeException(non vérifiée) avec le message"Age cannot be negative: " + agesi l'âge est inférieur à 0. Si l'âge est inférieur à 18, levez uneInvalidAgeException(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 avecthrows InvalidAgeException.verifyAgeUncheckedOnly(int age)- Cette méthode utilise uniquement des exceptions non vérifiées. Si l'âge est négatif, levez uneNegativeAgeExceptionavec le même format de message. Si l'âge est inférieur à 18, levez uneIllegalArgumentExceptionavec le message"Too young: " + age. Sinon, affichez"Age " + age + " verified (unchecked method)". Remarquez que cette méthode n'a pas besoin de déclarationthrows!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 appelezverifyAgeavec l'âge saisi. Comme elle lève une exception vérifiée, vous devez l'envelopper dans un bloc try-catch. InterceptezInvalidAgeExceptionet affichez"Checked exception caught: " + e.getMessage(). Interceptez égalementNegativeAgeExceptionet affichez"Unchecked exception caught: " + e.getMessage().Ensuite, affichez une ligne vide et
"=== Unchecked Exception Method ===". AppelezverifyAgeUncheckedOnlyavec 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. InterceptezNegativeAgeExceptionet affichez"Runtime exception caught: " + e.getMessage(). InterceptezIllegalArgumentExceptionet 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]"
}
}
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
1Fondamentaux de la POO
Fichiers externesIntroduction à la POOClasses vs ObjetsLe mot-clé thisMéthodesChamps (Attributs)Méthode constructeurSurcharge de constructeurRécapitulatif - Calculatrice simple4Héritage
Héritage de base (extends)Le mot-clé superRedéfinition de méthode (@Override)Chaînage de constructeursLa classe ObjectHéritage simple et multiniveauPourquoi pas d'héritage multiple de classesRécapitulatif - Hiérarchie des employés7Méthodes spéciales et classe Object
Méthode toString()equals() et hashCode()Méthode clone()compareTo() et ComparableInterface ComparatorRécapitulatif - Tri personnalisé10Gestion des exceptions en POO
Hiérarchie des classes d'exceptionExceptions personnaliséesErreurs Checked vs UncheckedPattern Try-with-resourcesRécapitulatif - Utilisateur validé2Modificateurs d'accès et Encapsulation
Aperçu des niveaux d'accèsMéthodes Getter et SetterMasquage d'informationsLe mot-clé finalRécapitulatif - Gestionnaire de compte bancaire5Polymorphisme
Bases de la surcharge de méthodesRedéfinition de méthodes (Run-Time)Upcasting et DowncastingL'opérateur instanceofClasses et méthodes abstraitesRécapitulatif - Calculateur de formes8Concepts avancés de la POO
Composition vs HéritageAgrégation vs CompositionClasses internes, imbriquées et anonymesEnums et méthodes d'EnumRecords (Java 16+)Classes scellées (Java 17+)11Patrons de conception, partie 1
Introduction aux patrons de conceptionPatron SingletonPatron FabriquePatron MonteurPatron ObservateurPatron Stratégie3Propriétés de classe et membres statiques
Variables d'instance vs variables statiquesMéthodes statiquesBlocs statiquesConstantes (static final)Récapitulatif - Compteur et utilitaire6Interfaces et Classes Abstraites
Introduction aux InterfacesImplémentation d'InterfacesImplémentation d'Interfaces MultiplesDefault et Static dans les InterfacesClasses Abstraites vs InterfacesInterfaces FonctionnellesRécapitulatif - Système de Paiement9La généricité
Introduction à la généricitéClasses génériquesMéthodes génériquesParamètres de type bornésWildcards (?, extends, super)Récapitulatif - Conteneur générique12Patrons de conception, partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositePatron Itérateur