Menu

Les exceptions en Java : erreurs, traces de pile et lancement

Ce qu'est une exception en Java, comment lire une trace de pile, la distinction entre exceptions contrôlées et non contrôlées, la hiérarchie des exceptions et comment lancer les vôtres.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Ce qu'est une exception

Une exception est la façon qu'a Java de dire « quelque chose a mal tourné et je ne peux pas continuer normalement ». Au lieu de renvoyer une valeur erronée ou de corrompre silencieusement vos données, le moteur d'exécution crée un objet exception qui décrit le problème et le lance. L'exécution normale s'arrête à ce point, et Java se met à chercher du code qui sait comment gérer la situation.

Si personne ne la traite, l'exception atteint le sommet de votre programme, la JVM affiche une trace de pile, et le processus se termine avec un statut différent de zéro.

Remarquez que "after" n'est jamais affiché. À l'instant où numbers[5] est évalué, une ArrayIndexOutOfBoundsException est lancée et le reste de main est abandonné.

Lire une trace de pile

Lorsqu'une exception reste non traitée, vous obtenez une sortie comme celle-ci. Elle a l'air intimidante, mais ce n'est qu'une liste :

Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Main.divide(Main.java:8)
	at Main.main(Main.java:4)

Lisez-la de haut en bas :

  • La première ligne est le type (ArithmeticException) et un message (/ by zero).
  • Chaque ligne at ... est un cadre de pile. Celle du haut est l'endroit où l'exception a réellement été lancée - divide à la ligne 8. En dessous se trouve l'appelant, main à la ligne 4.

La ligne at du haut est l'endroit où vous regardez en premier. Les cadres situés en dessous répondent à la question « comment en est-on arrivé là ? ».

Exécutez ceci et la trace pointe directement vers la ligne a / b, puis affiche main comme appelant. Cette chaîne d'appels est l'outil de débogage le plus utile que Java vous offre gratuitement.

La hiérarchie des exceptions

Toute exception est un objet, et elles descendent toutes de Throwable. Les deux branches qui comptent :

  • Error - des problèmes graves levés par la JVM, comme OutOfMemoryError ou StackOverflowError. En général, vous ne les capturez pas.
  • Exception - des problèmes que votre programme peut raisonnablement anticiper et gérer. À l'intérieur se trouve RuntimeException, le parent des bogues du quotidien comme NullPointerException.
Throwable
├── Error                 (don't catch: OutOfMemoryError, StackOverflowError)
└── Exception
    ├── IOException        (checked)
    ├── SQLException       (checked)
    └── RuntimeException   (unchecked)
        ├── NullPointerException
        ├── ArithmeticException
        └── ArrayIndexOutOfBoundsException

Comme ce sont de vraies classes, une exception peut transporter un message et vous pouvez l'interroger sur elle-même :

getMessage() renvoie le texte qui suit les deux-points dans la trace de pile ; getClass().getSimpleName() vous donne le type de l'exception par son nom.

Contrôlées vs non contrôlées

C'est la distinction qui déroute le plus les débutants.

  • Les exceptions non contrôlées étendent RuntimeException. Elles signifient généralement un bogue dans votre code - un null que vous n'attendiez pas, un mauvais indice, une division par zéro. Le compilateur ne vous oblige pas à les gérer.
  • Les exceptions contrôlées étendent Exception mais pas RuntimeException (par exemple IOException). Elles représentent des conditions hors de votre contrôle - un fichier manquant, une connexion réseau interrompue. Le compilateur vous oblige à les capturer ou à les déclarer.

Si une méthode peut lancer une exception contrôlée, elle doit le signaler avec throws, et chaque appelant doit s'en occuper :

Retirez throws Exception de main et le code ne compilera même pas - c'est le compilateur qui impose le contrat des exceptions contrôlées. Les exceptions non contrôlées n'exigent jamais cela.

Lancer les vôtres

Vous ne faites pas que réagir aux exceptions - vous pouvez aussi les déclencher. Utilisez throw avec un nouvel objet exception pour signaler qu'un argument ou un état est invalide. C'est bien mieux que de renvoyer une valeur magique comme -1 en espérant que l'appelant la vérifie.

Incluez toujours un message qui explique ce qui n'allait pas et, idéalement, la valeur fautive - votre futur vous, en lisant la trace de pile, vous en remerciera. IllegalArgumentException et IllegalStateException sont les deux auxquelles vous recourrez le plus souvent pour valider des entrées.

Pièges courants

  • Avaler les exceptions. Capturer une exception sans rien faire (un bloc vide) masque les bogues. Au minimum, journalisez-la ; le plus souvent, vous devriez la gérer ou la relancer.
  • Capturer Exception de façon trop large. Capturer la classe de base Exception (ou pire, Throwable) peut masquer des problèmes que vous n'aviez pas l'intention de gérer. Capturez le type précis que vous attendez.
  • Lire la trace de bas en haut. Le cadre le plus pertinent est la ligne at du haut, pas celle du bas. Commencez par là.
  • Confondre Error et Exception. N'essayez pas de récupérer après une OutOfMemoryError ou une StackOverflowError ; corrigez plutôt la cause sous-jacente.

Suite : try-catch

Vous savez maintenant ce que sont les exceptions et comment les lire. La page suivante explique comment réellement les traiter : envelopper le code à risque dans un bloc try, récupérer dans catch, et exécuter du code de nettoyage dans finally pour que votre programme continue au lieu de planter.

Questions fréquentes

Qu'est-ce qu'une exception en Java ?

Une exception est un objet qui représente un problème détecté pendant l'exécution d'un programme - comme une division par zéro, un accès au-delà de la fin d'un tableau, ou l'appel d'une méthode sur null. Lorsque le problème survient, Java lance l'exception : il interrompt le flux normal et cherche du code capable de la traiter. Si rien ne la traite, le programme affiche une trace de pile et s'arrête.

Quelle est la différence entre une exception contrôlée et une exception non contrôlée en Java ?

Les exceptions contrôlées (sous-classes d'Exception mais pas de RuntimeException, par exemple IOException) doivent être soit capturées, soit déclarées avec throws - le compilateur l'impose. Les exceptions non contrôlées (sous-classes de RuntimeException, par exemple NullPointerException, ArrayIndexOutOfBoundsException) signalent généralement des bogues de programmation et n'ont pas besoin d'être déclarées. Error (comme OutOfMemoryError) est également non contrôlée et, en général, n'est pas destinée à être capturée.

Comment lire une trace de pile en Java ?

Lisez-la de haut en bas. La première ligne indique le type de l'exception et le message (par exemple java.lang.ArithmeticException: / by zero). Chaque ligne at ... en dessous est un cadre de pile qui montre la méthode, le fichier et le numéro de ligne, en partant de l'endroit où l'exception a été lancée et en remontant à travers les appelants. La ligne at du haut est presque toujours l'endroit où regarder en premier.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER