La notion d'exception décrit des situations où la procédure normale d'évaluation des expressions n'est pas pertinente. Cette procédure suppose que l'évaluation d'une expression (par exemple, d'une invocation de méthode) résulte en la production d'une valeur. Il y a des cas où une valeur n'est pas obtenue, quand la procédure d'évaluation conduirait à exécuter une opération qui ne peut pas ou ne doit pas être réalisée :
Il est donc possible que l'évaluation d'une expression, au lieu de retourner une valeur, déclenche une exception. Certaines de ces exceptions sont des erreurs, qui conduisent fatalement à une fin prématurée du programme. D'autres peuvent être récupérées pour permettre la poursuite du programme.
En Java, les exceptions sont représentées par des objets de classe Throwable. La sous-classe Error est formée des exceptions qui ne sont pas considérées comme récupérables ; elles concernent les opérations de la machine virtuelle Java.
La sous-classe Exception est formée des exceptions considérées comme récupérables. Cependant, les objets de la sous-classe RuntimeException d'Exception ne sont pas obligatoirement récupérables : cette sous-classe comporte les exceptions
Considérons l'implémentation d'une pile par un tableau. Les opérations d'empilage et de dépilage peuvent conduire à exécuter une écriture ou une lecture en dehors des bornes du tableau. Ces opérations ne seront pas réalisées et déclencheront une IndexOutOfBoundsException, qui n'est pas obligatoirement récupérable.
Cependant, une écriture en dehors du tableau, demandée par un empilage, n'est une erreur que dans la mesure où la taille du tableau, choisie a priori, n'est pas assez grande. Plutôt que de sortir brutalement du programme, on peut créer un nouveau tableau de taille double, copier le contenu du tableau précédent dans le nouveau, et continuer avec celui-ci ; cette exception est donc récupérable par la méthode d'empilage. Mieux : on n'utilise pas de tableau, mais le type java.List.
Par contre, la lecture en dehors du tableau (à l'indice -1), qui provoque la même exception, est due à une erreur de conception de l'algorithme utilisant la pile ; il ne revient donc pas aux opérations de la pile de récupérer cette exception ; par contre, la fonction qui demande un dépilage devrait, éventuellement, récupérer cette exception.
public class PileVideException extends Exception { PileVideException(Pile p) { super("Pile vide"); } }
Une méthode dont le corps est susceptible de lever une exception contrôlée doit :
Cette indication, sous la forme d'une liste d'exceptions, intervient dans la relation de typage. La récupération minimale, qui gobe n'importe quelle exception, sans rien dire, est :
try { ... } catch (Exception e) {}
Une version plus informative de cette récupération minimale consiste à imprimer la chaîne de caractères décrivant l'exception sur le flot de sortie en erreur standard, par System.err.println(e), ou mieux, à imprimer l'état de la pile :
try { ... } catch (Exception e) { e.printStackTrace() }
La déclaration d'une exception se fait dans l'en-tête de la méthode, à la fois dans sa déclaration, dans une interface :
Object sommet() throws PileVideException;
et dans son implémentation :
public Object sommet() throws PileVideException { if (!estVide()) return contenu.get(contenu.size()-1); else throw new PileVideException(this); }
L'exécution du throw provoque d'une part la sortie immédiate de la méthode, et d'autre part le dépilage des appels jusqu'à ce qu'apparaisse un cadre d'invocation d'une méthode contenant un catch : l'exception est donc propagée le long de la chaîne invocations tant qu'elle n'est pas récupérée. Ce mécanisme de transmission est distinct du mécanisme usuel de retour d'une méthode. Si l'exception n'est jamais récupérée, le programme termine anormalement.
La récupération et le traitement sont réalisés en plaçant les appels susceptibles de déclencher une exception dans un try ... catch :
try { // p.empiler(a); // invocation protégée } catch (PileVideException e) { // récupération d'exception e.printStackTrace(); // traitement de l'exception }
Ce style de programmation est nécessaire dans des logiciels qui doivent être robustes.