En programmation Java, une exception est un événement qui interrompt le flux normal des instructions pendant l'exécution d'un programme. Une gestion efficace des exceptions est cruciale pour créer des applications robustes et fiables. Cet article détaille le fonctionnement, la hiérarchie et les meilleures pratiques liées aux exceptions.
Comprendre la hiérarchie des exceptions
Toutes les exceptions en Java dérivent de la classe java.lang.Throwable. Cette classe se divise en deux branches principales :
- Error : Représente des problèmes graves liés à la JVM (comme
OutOfMemoryError). Ces erreurs ne sont généralement pas destinées à être capturées par l'application. - Exception : Représente des conditions que l'application peut vouloir capturer. Elle se divise elle-même en :
- Exceptions contrôlées (Checked) : Héritent de
Exceptionmais pas deRuntimeException. Le compilateur oblige à les traiter (viatry-catchouthrows). - Exceptions non contrôlées (Unchecked) : Héritent de
RuntimeException. Leur capture est facultative au niveau de la compilation.
- Exceptions contrôlées (Checked) : Héritent de
Exemples courants d'exceptions
ArithmeticException: Lancée lors d'une opération mathématique invalide, comme une division par zéro sur des entiers.NullPointerException: Se produit lorsqu'on tente d'acéder à un membre d'un objet qui estnull.ArrayIndexOutOfBoundsException: Apparaît lors de l'accès à un index de tableau inexistant.
Structure de base du traitement : try, catch et finally
Pour intercepter une erreur sans inetrrompre le programme, on utilise un bloc try...catch. Le bloc finally, optionnel, s'exécute systématiquement, qu'une exception ait été levée ou non.
public class DemoException {
public static void main(String[] args) {
System.out.println("Début du programme");
try {
int numerateur = 50;
int denominateur = 0;
int resultat = numerateur / denominateur;
System.out.println("Résultat : " + resultat);
} catch (ArithmeticException e) {
System.err.println("Erreur détectée : " + e.getMessage());
e.printStackTrace();
} finally {
System.out.println("Opération terminée (bloc finally).");
}
System.out.println("Fin du programme");
}
}
Gestion multi-exceptions
Un seul bloc try peut être suivi de plusieurs blocs catch pour traiter différents types d'erreurs spécifiquement. Il est important de placer les exceptions les plus spécifiques avant les exceptions générales (comme Exception).
public class MultiCapture {
public static void main(String[] args) {
try {
String[] donnees = {"10", "0"};
int a = Integer.parseInt(donnees[0]);
int b = Integer.parseInt(donnees[1]);
System.out.println("Division : " + (a / b));
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Erreur : Paramètre manquant dans le tableau.");
} catch (NumberFormatException e) {
System.out.println("Erreur : Le format du nombre est invalide.");
} catch (Exception e) {
System.out.println("Une erreur inattendue est survenue : " + e.getMessage());
}
}
}
Les mots-clés throw et throws
Alors que catch sert à traiter l'exception, throw et throws servent à la signaler.
- throws : Utilisé dans la signature d'une méthode pour avertir que cette méthode peut générer certaines exceptions.
- throw : Utilisé à l'intérieur du corps d'une méthode pour instancier et lancer explicitement une exception.
class Calculateur {
// La méthode délègue la responsabilité de l'exception à l'appelant
public static int diviser(int x, int y) throws Exception {
if (y == 0) {
throw new Exception("Le diviseur ne peut pas être nul.");
}
return x / y;
}
}
public class TestPropagation {
public static void main(String[] args) {
try {
int res = Calculateur.diviser(10, 0);
System.out.println(res);
} catch (Exception e) {
System.out.println("Interception dans le main : " + e.getMessage());
}
}
}
Création d'exceptions personnalisées
Dans le cadre de la logique métier, il est souvent nécessaire de définir ses propres types d'erreurs. Pour cela, il suffit de créer une classe héritant de Exception (pour une exception contrôlée) ou de RuntimeException.
class AgeInvalideException extends Exception {
public AgeInvalideException(String message) {
super(message);
}
}
public class VerificationUtilisateur {
public static void validerAge(int age) throws AgeInvalideException {
if (age < 18) {
throw new AgeInvalideException("Accès refusé : Moins de 18 ans.");
}
}
public static void main(String[] args) {
try {
validerAge(15);
} catch (AgeInvalideException e) {
System.out.println("Exception métier : " + e.getMessage());
}
}
}
Différence entre Exception et RuntimeException
La distinction majeure réside dans la contrainte de traitement. Une Exception standard doit être gérée immédiatement au moment de l'écriture du code, sinon le programme ne compilera pas. Une RuntimeException (comme NullPointerException ou ClassCastException) est considérée comme une erreur de programmation qui peut être évitée par une meilleure logique de code, rendant son traitement par try-catch optionnel.