Les erreurs et les exceptions
Présentation
Lorsqu’un développeur écrit du code, il se peut qu’il produise des erreurs. Ces erreurs peuvent se diviser en deux catégories :
-
Les erreurs détectées au moment de la compilation, c’est-à-dire lorsque l’ordinateur transforme le programme informatique en un code exécutable.
-
Les erreurs survenant lors de l’exécution du programme.
Les erreurs détectées à la compilation
Les erreurs détectées lors de l’étape de la compilation sont présentes en raison d’erreurs commises par le développeur. Il peut s’agir d’une erreur de syntaxe, un mot-clé mal orthographié par exemple, ou d’une erreur sémantique, une variable non initialisée avant son utilisation par exemple. Ces erreurs peuvent avoir l’un des deux niveaux de gravité suivants.
-
Avertissement : le code exécutable de l’application peut être généré malgré cette erreur. Par exemple, la déclaration d’une variable qui n’est pas utilisée par la suite provoque un avertissement.
-
Erreur : le code exécutable ne peut être généré en raison de cette erreur. Par exemple, le type du paramètre passé à une méthode ne correspond pas à celui attendu.
L’ensemble de ces erreurs doivent être corrigées par le développeur.
Même si un avertissement n’empêche pas la compilation de votre code, il est toujours préférable de le corriger.
Les messages d’erreur expliquent la cause de l’erreur et permettent au développeur de comprendre ce qui pose problème. Les IDE proposent souvent des aides pour résoudre ces erreurs. Attention...
Les erreurs détectées à l’exécution
Bien qu’aucune erreur n’ait été détectée à la compilation, il est possible que des erreurs surviennent lors de l’exécution du programme. Ces erreurs se partagent en deux catégories :
-
D’un côté, les erreurs irrécupérables : elles provoquent inévitablement l’arrêt du programme.
-
D’un autre côté, les exceptions : ce sont les erreurs qui peuvent être traitées par le code afin de poursuivre l’exécution du programme.
1. Les erreurs irrécupérables
Voici deux exemples provoquant ce type d’erreur.
a. La saturation de la pile des appels de méthodes
Lorsqu’un développeur fait un appel récursif infini à une méthode, le programme compile. Mais lors de l’exécution, une erreur irrécupérable survient. En Java, c’est le message suivant qui s’affiche :
Exception in thread "main" java.lang.StackOverflowError
Exemple de code provoquant cette erreur :
public class PbPile {
public static void main(String[] args) {
a();
}
private static void a() {
a();
}
}
Dans ce code, la méthode a() est appelée une première fois et ensuite elle fait appel à elle-même, ce qui fait qu’elle s’appelle à nouveau elle-même, et ainsi de suite. Les appels à la méthode a() s’empilent jusqu’à ce que la pile des appels de méthode sature et provoque l’erreur fatale.
b. La saturation de la mémoire
Lorsqu’il y a eu trop de demandes d’utilisation de mémoire, cela n’empêche pas la compilation du programme. Mais lors de l’exécution, la machine virtuelle aura sa mémoire saturée. Cela provoque l’erreur suivante :
Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
Exemple de code provoquant cette erreur :
public class PbMemoire {
public static void main(String[] args) {
...
Exercices
1. Le calcul de la racine carrée
Soit la fonction racineCarrée() calculant la racine carrée du nombre passé en paramètre. Cette fonction lève une exception si son paramètre est négatif. Il ne vous est pas demandé d’écrire cette fonction, vous supposez qu’elle existe déjà.
Écrire un algorithme qui calcule la racine carrée d’un nombre saisi par l’utilisateur.
Affichage et saisie (exécution normale) : |
Entrer une valeur : 25 |
√25 = 5 |
|
Affichage et saisie (exécution non normale) : |
Entrer une valeur : -3 |
La racine carrée n’est pas définie pour un nombre négatif. |
2. La calculatrice en Java
L’objectif est de créer une mini calculatrice réalisant des opérations d’addition, de soustraction, de multiplication, de division entière et de reste de celle-ci.
Cette calculatrice manipule des entiers de type int. Avec le type int, les valeurs doivent être comprises entre -2 147 483 648 et 2 147 483 647. Si une variable de type int est initialisée à 2 000 000 000 et que la variable est multipliée par deux, la variable contiendra -294 967 296 ! Il y a eu un "dépassement de capacité". Cela ne provoque malheureusement ni erreur ni levée d’exception.
Un autre problème avec les opérations sur les entiers est que la division par zéro n’est pas mathématiquement définie. Lorsqu’une telle opération est réalisée, une exception de type ArithmeticException est levée.
La calculatrice devra prendre en compte cela pour éviter d’afficher un résultat faux.
a. Création d’une classe DepassementCapaciteException
Cette classe est utilisée pour représenter une exception contrôlée. Le message associé est "Le résultat dépasse la capacité de la calculatrice"....
Solutions des exercices
1. Le calcul de la racine carrée
Algo calculRacineCarree
# Saisie d'une valeur et calcul de sa racine carrée
Variable val : entier
Début
val <- saisir("Entrer une valeur : ")
Tenter
écrire("√", val, " = ", racineCarrée(val))
TraiterException
écrire("La racine carrée n'est pas définie pour un nombre négatif")
FTenter
Fin
2. La calculatrice en Java
a. Création d’une classe DepassementCapaciteException
package fr.eni.calculatrice;
public class DepassementCapaciteException extends Exception {
private static final long serialVersionUID = 1L;
public DepassementCapaciteException() {
super("Le résultat dépasse la capacité de la calculatrice");
}
}
Cette classe hérite de la classe Exception, ainsi, cela en fait une exception contrôlée : il sera nécessaire soit de traiter l’exception, soit de la propager.
b. Création de la classe utilitaire Operation
package fr.eni.calculatrice;
public class Operation {
public static int ajouter(int a, int b) throws
DepassementCapaciteException {
long resLong = (long) a + b;
int resInt = a + b;
if (resLong != resInt)
throw new DepassementCapaciteException();
return resInt;
}
public static int soustraire(int a, int b) throws
DepassementCapaciteException {
long resLong = (long) a - b;
int resInt = a - b;
if (resLong != resInt)
...