Introduction
Une exception est un événement d’erreur qui peut se produire pendant l’exécution d’un programme et perturber son flux normal. Java offre une manière robuste et orientée objet de gérer les scénarios d’exception, connue sous le nom de gestion des exceptions en Java.
Les exceptions en Java peuvent survenir dans différentes situations, telles qu’une entrée de données incorrecte par l’utilisateur, une défaillance matérielle, une défaillance de la connexion réseau ou un serveur de base de données hors service. Le code qui spécifie quoi faire dans des scénarios d’exception spécifiques est appelé gestion des exceptions.
Lancer et Attraper les Exceptions
Java crée un objet exception lorsqu’une erreur se produit pendant l’exécution d’une instruction. L’objet exception contient beaucoup d’informations de débogage telles que la hiérarchie des méthodes, le numéro de ligne où l’exception s’est produite et le type d’exception.
Si une exception se produit dans une méthode, le processus de création de l’objet d’exception et de sa remise à l’environnement d’exécution est appelé “lancer l’exception”. Le flux normal du programme s’arrête et l’Environnement d’Exécution Java (JRE) tente de trouver le gestionnaire pour l’exception. Le gestionnaire d’exception est le bloc de code qui peut traiter l’objet d’exception.
- La logique pour trouver le gestionnaire d’exception commence par la recherche dans la méthode où l’erreur s’est produite.
- Si aucun gestionnaire approprié n’est trouvé, alors il passera à la méthode appelante.
- Et ainsi de suite.
Donc, si la pile d’appels de méthode est A->B->C
et qu’une exception est levée dans la méthode C
, alors la recherche du gestionnaire approprié se déplacera de C->B->A
.
Si un gestionnaire d’exception approprié est trouvé, l’objet d’exception est transmis au gestionnaire pour le traiter. Le gestionnaire est dit “attraper l’exception”. S’il n’y a pas de gestionnaire d’exception approprié, alors le programme se termine et imprime des informations sur l’exception dans la console.
Le cadre de gestion des exceptions Java est utilisé pour gérer uniquement les erreurs d’exécution. Les erreurs de compilation doivent être corrigées par le développeur écrivant le code sinon le programme ne s’exécutera pas.
Mots-clés de Gestion des Exceptions Java
Java fournit des mots-clés spécifiques à des fins de gestion des exceptions.
-
throw – Nous savons que si une erreur se produit, un objet exception est créé, puis le runtime Java commence à les gérer. Parfois, nous voulons générer des exceptions explicitement dans notre code. Par exemple, dans un programme d’authentification utilisateur, nous devrions générer des exceptions pour les clients si le mot de passe est
null
. Le mot-cléthrow
est utilisé pour lancer des exceptions vers le runtime afin de les gérer. -
throws – Lorsque nous lançons une exception dans une méthode et que nous ne la gérons pas, nous devons utiliser le mot-clé
throws
dans la signature de la méthode pour informer le programme appelant des exceptions qui pourraient être lancées par la méthode. La méthode appelante peut gérer ces exceptions ou les propager à sa méthode appelante en utilisant le mot-cléthrows
. Nous pouvons fournir plusieurs exceptions dans la clausethrows
, et elle peut être utilisée avec la méthodemain()
également. -
try-catch – Nous utilisons le bloc
try-catch
pour la gestion des exceptions dans notre code.try
marque le début du bloc etcatch
se trouve à la fin du bloctry
pour gérer les exceptions. Nous pouvons avoir plusieurs blocscatch
avec un bloctry
. Le bloctry-catch
peut également être imbriqué. Le bloccatch
nécessite un paramètre qui doit être de typeException
. - Enfin – le bloc
finally
est facultatif et peut être utilisé uniquement avec un bloctry-catch
. Puisque l’exception interrompt le processus d’exécution, nous pourrions avoir des ressources ouvertes qui ne seront pas fermées, donc nous pouvons utiliser le blocfinally
. Le blocfinally
est toujours exécuté, que qu’une exception se soit produite ou non.
Un exemple de gestion des exceptions
- La méthode
testException()
lance des exceptions en utilisant le mot-cléthrow
. La signature de la méthode utilise le mot-cléthrows
pour indiquer au programme appelant le type d’exceptions qu’elle pourrait lancer. - Dans la méthode
main()
, je gère les exceptions en utilisant un bloctry-catch
. Lorsque je ne les gère pas, je les propage à l’exécution avec la clausethrows
dans la méthodemain()
. - La méthode
testException(-10)
ne s’exécute jamais en raison de l’exception, puis le blocfinally
est exécuté.
La méthode printStackTrace()
est l’une des méthodes utiles de la classe Exception
à des fins de débogage.
Ce code produira la sortie suivante :
Outputjava.io.FileNotFoundException: Negative Integer -5
at com.journaldev.exceptions.ExceptionHandling.testException(ExceptionHandling.java:24)
at com.journaldev.exceptions.ExceptionHandling.main(ExceptionHandling.java:10)
Releasing resources
Exception in thread "main" java.io.IOException: Only supported for index 0 to 10
at com.journaldev.exceptions.ExceptionHandling.testException(ExceptionHandling.java:27)
at com.journaldev.exceptions.ExceptionHandling.main(ExceptionHandling.java:19)
Quelques points importants à noter :
- Nous ne pouvons pas avoir de clause
catch
oufinally
sans un bloctry
. - A
try
statement should have eithercatch
block orfinally
block, it can have both blocks. - Nous ne pouvons pas écrire de code entre les blocs
try-catch-finally
. - Nous pouvons avoir plusieurs blocs
catch
avec une seule instructiontry
. - Les blocs
try-catch
peuvent être imbriqués de manière similaire aux instructionsif-else
. - Nous ne pouvons avoir qu’un seul bloc
finally
avec une instructiontry-catch
.
Hiérarchie des exceptions Java
Comme indiqué précédemment, lorsqu’une exception est déclenchée, un objet d’exception est créé. Les exceptions Java sont hiérarchisées et l’héritage est utilisé pour catégoriser différents types d’exceptions. Throwable
est la classe parente de la hiérarchie des exceptions Java et elle a deux objets enfants – Error
et Exception
. Les Exception
s sont ensuite divisées en Exception
s vérifiées et Exception
s d’exécution.
- Erreurs: Les
Error
s sont des scénarios exceptionnels qui échappent à la portée de l’application et il n’est pas possible de les anticiper et de s’en remettre. Par exemple, une défaillance matérielle, un crash de la machine virtuelle Java (JVM) ou une erreur d’insuffisance de mémoire. C’est pourquoi nous avons une hiérarchie distincte deError
s et nous ne devrions pas essayer de gérer ces situations. Certaines desError
s courantes sontOutOfMemoryError
etStackOverflowError
. - Exceptions vérifiées: Les exceptions vérifiées sont des scénarios exceptionnels que nous pouvons anticiper dans un programme et essayer de récupérer. Par exemple, FileNotFoundException. Nous devrions capturer cette exception et fournir un message utile à l’utilisateur et le journaliser correctement à des fins de débogage. L’Exception est la classe parent de toutes les Exceptions vérifiées. Si nous lançons une Exception vérifiée, nous devons la capturer dans la même méthode, ou nous devons la propager à l’appelant en utilisant le mot-clé throws.
- Exception de Runtime: Les exceptions de Runtime sont causées par une mauvaise programmation. Par exemple, essayer de récupérer un élément d’un tableau. Nous devrions d’abord vérifier la longueur du tableau avant d’essayer de récupérer l’élément, sinon cela pourrait déclencher ArrayIndexOutOfBoundException à l’exécution. RuntimeException est la classe parent de toutes les exceptions de Runtime. Si nous lançons une Exception de Runtime dans une méthode, il n’est pas nécessaire de les spécifier dans la clause de signature de méthode throws. Les exceptions de runtime peuvent être évitées avec une meilleure programmation.
Quelques méthodes utiles des classes d’exception
Java Exception
et toutes ses sous-classes ne fournissent aucune méthode spécifique, et toutes les méthodes sont définies dans la classe de base – Throwable
. Les classes Exception
sont créées pour spécifier différents types de scénarios d’Exception
afin que nous puissions facilement identifier la cause principale et gérer l’Exception
selon son type. La classe Throwable
implémente l’interface Serializable
pour l’interopérabilité.
Certains des méthodes utiles de la classe Throwable
sont :
- public String getMessage() – Cette méthode renvoie le message
String
deThrowable
et le message peut être fourni lors de la création de l’exception via son constructeur. - public String getLocalizedMessage() – Cette méthode est fournie afin que les sous-classes puissent la remplacer pour fournir un message spécifique à la locale au programme appelant. L’implémentation de cette méthode dans la classe
Throwable
utilise la méthodegetMessage()
pour renvoyer le message d’exception. - public synchronized Throwable getCause() – Cette méthode renvoie la cause de l’exception ou
null
si la cause est inconnue. - public String toString() – Cette méthode renvoie les informations sur
Throwable
au formatString
, laString
renvoyée contient le nom de la classeThrowable
et le message localisé. - public void printStackTrace() – Cette méthode imprime les informations de la trace de la pile sur le flux d’erreur standard. Cette méthode est surchargée, et nous pouvons passer
PrintStream
ouPrintWriter
en argument pour écrire les informations de la trace de la pile dans un fichier ou un flux.
Gestion automatique des ressources Java 7 et améliorations des blocs catch
Si vous catch
ez beaucoup d’exceptions dans un seul bloc try
, vous remarquerez que le code du bloc catch
consiste principalement en un code redondant pour journaliser l’erreur. En Java 7, l’une des fonctionnalités était un bloc catch
amélioré où nous pouvons attraper plusieurs exceptions dans un seul bloc catch
. Voici un exemple du bloc catch
avec cette fonctionnalité:
Il y a certaines contraintes telles que l’objet exception est final et que nous ne pouvons pas le modifier à l’intérieur du bloc catch
, lisez l’analyse complète sur Améliorations du bloc catch Java 7.
La plupart du temps, nous utilisons le bloc finally
simplement pour fermer les ressources. Parfois, nous oublions de les fermer et obtenons des exceptions d’exécution lorsque les ressources sont épuisées. Ces exceptions sont difficiles à déboguer, et nous pourrions avoir besoin de vérifier chaque endroit où nous utilisons cette ressource pour nous assurer que nous la fermons. En Java 7, l’une des améliorations était l’utilisation de try-with-resources
, où nous pouvons créer une ressource dans l’instruction try
elle-même et l’utiliser à l’intérieur du bloc try-catch
. Lorsque l’exécution sort du bloc try-catch
, l’environnement d’exécution ferme automatiquement ces ressources. Voici un exemple du bloc try-catch
avec cette amélioration :
A Custom Exception Class Example
Java nous fournit de nombreuses classes d’exceptions à utiliser, mais parfois nous devons créer nos propres classes d’exceptions personnalisées. Par exemple, pour informer l’appelant d’un type spécifique d’exception avec le message approprié. Nous pouvons avoir des champs personnalisés pour le suivi, tels que des codes d’erreur. Supposons que nous écrivions une méthode pour traiter uniquement les fichiers texte, nous pouvons fournir à l’appelant le code d’erreur approprié lorsqu’un autre type de fichier est envoyé en entrée.
Tout d’abord, créez MyException
:
Ensuite, créez un CustomExceptionExample
:
Nous pouvons avoir une méthode distincte pour traiter différents types de codes d’erreur que nous obtenons de différentes méthodes. Certains d’entre eux sont consommés car nous ne voulons peut-être pas informer l’utilisateur, ou certains d’entre eux seront renvoyés pour informer l’utilisateur du problème.
Voici j’étends Exception
de sorte que chaque fois que cette exception est produite, elle doit être traitée dans la méthode ou renvoyée au programme appelant. Si nous étendons RuntimeException
, il n’est pas nécessaire de le spécifier dans la clause throws
.
C’était une décision de conception. L’utilisation des exceptions vérifiées a l’avantage d’aider les développeurs à comprendre les exceptions auxquelles ils peuvent s’attendre et à prendre les mesures appropriées pour les gérer.
Meilleures pratiques pour la gestion des exceptions en Java
- Utiliser des exceptions spécifiques – Les classes de base de la hiérarchie des exceptions ne fournissent aucune information utile, c’est pourquoi Java a tant de classes d’exceptions, telles que
IOException
avec des sous-classes supplémentaires telles queFileNotFoundException
,EOFException
, etc. Nous devrions toujourslancer
etattraper
des classes d’exception spécifiques afin que l’appelant puisse connaître facilement la cause première de l’exception et les traiter. Cela rend le débogage plus facile et aide les applications clientes à gérer les exceptions de manière appropriée. - Lancer tôt ou échouer rapidement – Nous devrions essayer de
lancer
les exceptions le plus tôt possible. Considérons la méthodeprocessFile()
ci-dessus, si nous passons l’argumentnull
à cette méthode, nous obtiendrons l’exception suivante:
OutputException in thread "main" java.lang.NullPointerException
at java.io.FileInputStream.<init>(FileInputStream.java:134)
at java.io.FileInputStream.<init>(FileInputStream.java:97)
at com.journaldev.exceptions.CustomExceptionExample.processFile(CustomExceptionExample.java:42)
at com.journaldev.exceptions.CustomExceptionExample.main(CustomExceptionExample.java:12)
Pendant le débogage, nous devrons examiner attentivement la trace de la pile pour identifier l’emplacement réel de l’exception. Si nous modifions notre logique d’implémentation pour vérifier ces exceptions plus tôt comme ci-dessous :
, alors la trace de la pile d’exception indiquera où l’exception s’est produite avec un message clair :
Outputcom.journaldev.exceptions.MyException: File name can't be null
at com.journaldev.exceptions.CustomExceptionExample.processFile(CustomExceptionExample.java:37)
at com.journaldev.exceptions.CustomExceptionExample.main(CustomExceptionExample.java:12)
- Capture Tardive – Comme Java impose de traiter l’exception vérifiée ou de la déclarer dans la signature de la méthode, parfois les développeurs ont tendance à
catch
l’exception et à enregistrer l’erreur. Mais cette pratique est nuisible car le programme appelant ne reçoit aucune notification pour l’exception. Nous devrionscatch
les exceptions uniquement lorsque nous pouvons les gérer de manière appropriée. Par exemple, dans la méthode ci-dessus, jethrow
les exceptions vers la méthode appelante pour les gérer. La même méthode pourrait être utilisée par d’autres applications qui souhaitent peut-être traiter l’exception de manière différente. Lors de la mise en œuvre de toute fonctionnalité, nous devrions toujoursthrow
les exceptions vers l’appelant et les laisser décider comment les gérer. - Fermeture des Ressources – Comme les exceptions interrompent le traitement du programme, nous devrions fermer toutes les ressources dans le bloc finally ou utiliser l’amélioration
try-with-resources
de Java 7 pour laisser le moteur Java les fermer automatiquement. - Enregistrement des exceptions – Nous devrions toujours enregistrer les messages d’exception et, lors du lancement d’exceptions, fournir un message clair afin que l’appelant sache facilement pourquoi l’exception s’est produite. Nous devrions toujours éviter un bloc
catch
vide qui se contente de consommer l’exception et ne fournit aucun détail significatif de l’exception pour le débogage. - Bloc catch unique pour plusieurs exceptions – La plupart du temps, nous enregistrons les détails de l’exception et fournissons un message à l’utilisateur, dans ce cas, nous devrions utiliser la fonctionnalité Java 7 pour gérer plusieurs exceptions dans un seul bloc
catch
. Cette approche réduira la taille de notre code, et il semblera également plus propre. - Utilisation d’exceptions personnalisées – Il est toujours préférable de définir une stratégie de gestion des exceptions au moment de la conception et plutôt que de lancer et de capturer plusieurs exceptions, nous pouvons créer une exception personnalisée avec un code d’erreur, et le programme appelant peut gérer ces codes d’erreur. Il est également judicieux de créer une méthode utilitaire pour traiter différents codes d’erreur et les utiliser.
- Conventions de nommage et d’emballage – Lorsque vous créez votre exception personnalisée, assurez-vous qu’elle se termine par
Exception
afin qu’il soit clair dès le nom lui-même qu’il s’agit d’une classe d’exception. Assurez-vous également de les empaqueter comme c’est fait dans le kit de développement Java (JDK). Par exemple,IOException
est l’exception de base pour toutes les opérations d’entrée-sortie. - Utilisez les exceptions avec discernement – Les exceptions sont coûteuses, et parfois il n’est pas nécessaire de les déclencher du tout. On peut renvoyer une variable booléenne au programme appelant pour indiquer si une opération a réussi ou non. Cela est utile lorsque l’opération est facultative et que vous ne voulez pas que votre programme se bloque en cas d’échec. Par exemple, lors de la mise à jour des cotations boursières dans la base de données à partir d’un service web tiers, nous pouvons vouloir éviter de déclencher des exceptions si la connexion échoue.
- Documentez les exceptions déclenchées – Utilisez Javadoc
@throws
pour spécifier clairement les exceptions déclenchées par la méthode. Cela est très utile lorsque vous fournissez une interface pour que d’autres applications l’utilisent.
Conclusion
Dans cet article, vous avez appris le traitement des exceptions en Java. Vous avez appris à propos de throw
et throws
. Vous avez également appris sur les blocs try
(et try-with-resources
), catch
, et finally
.
Source:
https://www.digitalocean.com/community/tutorials/exception-handling-in-java