19. Exceptions et Gestion des Erreurs
Table des matières
- 19.1 Hiérarchie et types dexceptions
- 19.2 Déclarer et lancer des exceptions
- 19.3 Redéfinition de méthodes et règles sur les exceptions
- 19.4 Gestion des exceptions: try, catch, finally
- 19.5 Gestion automatique des ressources try-with-resources
- 19.6 Exceptions supprimées
- 19.7 Résumé des exceptions
Les Exceptions constituent le mécanisme structuré de Java pour gérer les conditions anormales à runtime.
Elles permettent de séparer le flux normal d'exécution de la logique de gestion des erreurs, améliorant la robustesse, la lisibilité et l'exactitude du programme.
19.1 Hiérarchie et types dexceptions
Toutes les exceptions dérivent de Throwable.
La hiérarchie définit quelles conditions sont récupérables, lesquelles doivent être déclarées, et lesquelles représentent des défaillances système fatales.
java.lang.Object
└── java.lang.Throwable
├── java.lang.Error
└── java.lang.Exception
└── java.lang.RuntimeException
19.1.1 Throwable
- Classe de base pour toutes les erreurs et exceptions
- Fournit message, cause et stack trace
- Seuls
Throwableet ses sous-classes peuvent être lancés ou capturés
19.1.2 Error (unchecked)
- Représente des problèmes graves de la JVM ou du système
- Non destiné à être capturé ou géré
- Exemples:
OutOfMemoryError,StackOverflowError
Note
Les erreurs indiquent des conditions dont l'application ne peut généralement pas se remettre.
19.1.3 Exceptions Checked (Exception)
- Sous-classes de
Exceptionà lexclusion deRuntimeException - Représentent des conditions que l'application peut vouloir gérer
- Doivent être soit capturées soit déclarées
- Exemples:
IOException,SQLException
19.1.4 Exceptions Unchecked (RuntimeException)
- Sous-classes de
RuntimeException - Ne doivent pas obligatoirement être déclarées ou capturées
- Représentent généralement des erreurs de programmation
- Exemples:
NullPointerException,IllegalArgumentException
19.2 Déclarer et lancer des exceptions
19.2.1 Déclarer des exceptions avec throws
Une méthode déclare les exceptions checked avec la clause throws. Cela fait partie du contrat API de la méthode.
void readFile(Path p) throws IOException {
Files.readString(p);
}
Note
- Seules les exceptions checked doivent être déclarées.
- Les exceptions unchecked peuvent l'être, mais sont généralement omises.
19.2.2 Lancer des exceptions
Les exceptions sont créées avec new et lancées explicitement avec throw.
if (value < 0) {
throw new IllegalArgumentException("value must be >= 0");
}
throwlance exactement une instance dexceptionthrowsdéclare les exceptions possibles dans la signature de la méthode
19.3 Redéfinition de méthodes et règles sur les exceptions
Lors de la redéfinition dune méthode, les règles sur les exceptions sont strictement appliquées :
- Une méthode redéfinie peut lancer moins d'exceptions checked ou des exceptions plus spécifiques
- Elle peut lancer n'importe quelles exceptions unchecked
- Elle ne peut lancer aucune nouvelle exception checked plus large
class Parent {
void work() throws IOException {}
}
class Child extends Parent {
@Override
void work() throws FileNotFoundException {} // OK
}
Note
Modifier uniquement les exceptions unchecked ne viole jamais le contrat de redéfinition.
Important
Rappel : les constructeurs suivent une règle différente.
Un Constructeur doit déclarer toutes les exceptions checked déclarées dans le constructeur de base (ou les superclasses de ces exceptions checked).
Il peut également déclarer des exceptions checked supplémentaires. Ce comportement est l’opposé de celui de l’overriding de méthodes.
Une méthode qui override ne peut pas lancer d’exception checked autre que celles déclarées par la méthode overridée. Elle ne peut lancer que des sous-classes de ces exceptions.
19.4 Gestion des exceptions: try, catch, finally
19.4.1 Syntaxe de base try-catch
try {
riskyOperation();
} catch (IOException e) {
handle(e);
}
- Un bloc
trydoit être suivi d'au moins uncatchou d'unfinally - Les
catchsont évalués de haut en bas
19.4.2 Plusieurs blocs catch
try {
process();
} catch (FileNotFoundException e) {
recover();
} catch (IOException e) {
log();
}
Note
Les exceptions plus spécifiques doivent précéder les plus générales, sinon la compilation échoue.
Si un catch pour une superclasse précède celui d'une sous-classe, ce dernier devient inatteignable.
19.4.3 Multi-catch Java-7
try {
process();
} catch (IOException | SQLException e) {
log(e);
}
- Les types d'exception doivent être non liés (pas parent/enfant)
- La variable capturée est implicitement
final
19.4.4 Bloc finally
Le bloc finally s'exécute qu'il y ait exception ou non, sauf en cas d'arrêt extrême de la JVM.
try {
open();
} finally {
close();
}
- Utilisé pour la logique de nettoyage
- S'exécute même si
returnest utilisé dans try ou catch
Note
Un bloc finally peut écraser une valeur de retour ou avaler une exception. Cela est déconseillé car cela complique le flux de contrôle.
Important
Lorsquun bloc catch et un bloc finally lancent tous deux une exception, lexception lancée dans le bloc finally est celle qui est propagée par la méthode.
Lexception lancée dans le bloc catch est perdue et nest pas ajoutée à la liste des exceptions supprimées.
try {
throw new RuntimeException("try");
} catch (RuntimeException e) {
throw new RuntimeException("catch");
} finally {
throw new RuntimeException("finally");
}
Dans ce cas, seule lexception "finally" est lancée.
19.5 Gestion automatique des ressources try-with-resources
Le try-with-resources permet la fermeture automatique des ressources implémentant AutoCloseable.
Il élimine le besoin d'un bloc finally explicite dans la plupart des cas.
19.5.1 Syntaxe de base
try (BufferedReader br = Files.newBufferedReader(path)) {
return br.readLine();
}
- Les ressources sont fermées automatiquement
- La fermeture a lieu même en cas d'exception
- Les ressources sont fermées avant l’exécution de tout bloc
catchoufinally.
try (Resource a = new Resource()) {
a.read();
} finally {
a.close(); // ❌ Compile-time error: a est hors de portée ici
}
19.5.2 Déclarer plusieurs ressources
try (InputStream in = Files.newInputStream(p);
OutputStream out = Files.newOutputStream(q)) {
in.transferTo(out);
}
- Les ressources sont fermées en ordre inverse de déclaration
19.5.3 Portée des ressources
- Les ressources sont visibles uniquement dans le bloc
try - Elles sont implicitement
final - Depuis Java 9, on peut déclarer les ressources avant le try-with-resources si elles sont
finalou effectivement finales
final var firstWriter = Files.newBufferedWriter(filePath);
try (firstWriter; var secondWriter = Files.newBufferedWriter(filePath)) {
// CODE
}
Note
Tenter de réaffecter une variable ressource provoque une erreur de compilation.
Resource a = new Resource();
try(a){ // since Java 9
...
}finally{
a.close(); // ce code compile, mais la ressource référencée par la référence `a` a déjà été fermée.
}
19.6 Exceptions supprimées
Lorsque le bloc try et la méthode close() d'une ressource lancent tous deux une exception, Java conserve l'exception principale et supprime les autres.
try (BadResource r = new BadResource()) {
throw new RuntimeException("main");
}
Si close() lance aussi une exception, elle devient supprimée.
catch (Exception e) {
for (Throwable t : e.getSuppressed()) {
System.out.println(t);
}
}
- L'exeption principale est lancée
- Les exceptions secondaires sont accessibles via
getSuppressed()
Important
Les exceptions supprimées sont générées uniquement par le bloc finally implicite créé par le try-with-resources.
En revanche, les exceptions lancées dans un bloc finally explicite ne sont pas supprimées : elles remplacent toute exception précédente et deviennent la seule exception propagée.
19.7 Résumé des exceptions
- Les exceptions checked doivent être capturées ou déclarées
- Les méthodes redéfinies ne peuvent pas élargir les exceptions checked
- Utiliser multi-catch pour une logique de gestion commune
- Préférer try-with-resources au nettoyage via finally
- Les ressources se ferment en ordre inverse
- Les exceptions supprimées préservent le contexte complet de défaillance