« Salut, Amigo. Nous allons étudier une leçon très intéressante aujourd'hui. Je vais te parler des exceptions.» Les exceptions sont un mécanisme spécial qui nous permet de gérer les erreurs dans le programme. Voici quelques exemples d'erreurs qui peuvent survenir dans un programme :

1. Le programme peut essayer d'écrire dans un fichier alors que le disque dur est complètement plein.

2. Le programme peut essayer d'appeler une méthode sur une variable qui stocke une référence null.

3. Le programme peut essayer de diviser un nombre par 0. »

Toutes ces actions causent des erreurs. En général, le résultat est que le programme se termine immédiatement, car il ne reviendrait à rien de continuer à exécuter du code dans ce cas.

« Pourquoi ? »

« Est-ce que ça servirait à quelque chose de continuer à tourner le volant si ta voiture a quitté la route et tombe d'une falaise ? »

« Alors le programme doit cesser son exécution ? »

« Oui. Du moins, c'était comme ça avant. Une erreur causait la fin du programme. »

« C'est une approche très intelligente. »

« Mais ce ne serait pas mieux d'essayer de continuer à exécuter le programme ? »

« Si. Mais supposons que tu as beaucoup de texte dans Word et que tu l'enregistres. L'opération d'enregistrement échoue, mais le programme te laisse penser que tout va bien. Tu continues alors à écrire. Ce serait idiot, non ? »

« Ouaip. »

« Donc les programmeurs ont pensé à une solution intéressante : chaque fonction renvoie l'état de son travail. 0 signifie que tout s'est passé comme attendu. Toute autre valeur signifie qu'une erreur s'est produite, et la valeur de retour est un code d'erreur. »

« Cependant, cette approche a aussi ses limites. Pour chaque (!) appel de fonction, tu dois vérifier le code (nombre) de retour. Pour commencer, ce n'est pas très pratique : le code de gestion des erreurs est rarement exécuté, mais il doit être inclus partout. Deuxièmement, les fonctions renvoient souvent diverses valeurs : qu'est-ce que tu vas faire avec ? »

« Exact. C'est ce que je me demandais aussi. »

« Et puis un beau jour, on a inventé un mécanisme d'exceptions et de gestion des erreurs. Voici comment cela fonctionne :

1. Quand une erreur se produit, la machine Java crée un objet spécial, une exception, où elle enregistre toutes les informations sur l'erreur. Il existe différentes exceptions pour différentes erreurs.

2. Une exception fait sortir le programme de sa fonction actuelle immédiatement, puis de la fonction suivante, et ainsi de suite, jusqu'à sortir de la méthode main. Ensuite, le programme se termine. C'est ce que les programmeurs appellent aussi le 'déroulement de la pile d'appels' par la machine Java. »

« Mais tu as dit que le programme ne se terminait pas toujours. »

« Oui, car il existe un moyen de capturer une exception. Nous pouvons écrire du code spécial au bon endroit pour capturer les exceptions qui nous intéressent et faire quelque chose avec. C'est quelque chose d'important. »

« Pour nous aider à faire cela, il existe une construction spéciale, try-catch. Voici comment cela fonctionne : »

Exemple d'un programme qui capture une exception (division par 0) et continue à fonctionner.
public class ExceptionExample2
{
    public static void main(String[] args)
    {
        System.out.println("Program starts");

        try
        {
            System.out.println("Before calling method1");
            method1();
            System.out.println("After calling method1. This will never be shown");
        }
        catch (Exception e)
        {
           System.out.println("Exception has been caught");
        }

        System.out.println("Program is still running");
    }

    public static void method1()
    {
        int a = 100;
        int b = 0;
        System.out.println(a / b);
    }
}
Sortie écran :

Program starts
Before method1 calling
Exception has been caught
Program is still running

« Mais pourquoi 'Après l'appel de methode1. Cela ne s'affichera jamais » ne s'affiche pas à l'écran ? »

« Merci d'avoir posé la question. À la ligne 25, nous divisons par 0, ce qui conduit à une erreur : une exception. La machine Java crée un objet ArithmeticException avec des informations sur l'erreur. L'objet est l'exception. »

« L'exception se produit à l'intérieur de la méthode method1. Cela cause l'arrêt immédiat de la méthode. La méthode main se terminerait également sans le bloc try-catch. »

« Si une exception se produit dans un bloc try, elle est capturée par le bloc catch. Le reste du code dans le bloc try n'est pas exécuté. Au lieu de cela, le bloc catch commence à être exécuté. »

« Je ne comprends pas. »

« En d'autres termes, le code fonctionne comme ceci :

1. Si une exception se produit dans un bloc try le code cesse de s'exécuter là où l'exception est survenue, et le bloc catch commence à être exécuté.

2. Si aucune exception ne se produit, le bloc try est exécuté jusqu'au bout, et le bloc catch n'est pas exécuté. »

« Hein ? »

« Imagine qu'après chaque appel de méthode nous vérifions si la méthode s'est bien terminée ou s'est conclue soudainement à cause d'une exception. Si une exception s'est produite, nous exécutons le bloc catch (s'il y en a un) pour capturer l'exception. S'il n'y a pas de bloc catch, nous terminons la méthode actuelle, et la méthode qui l'a appelée effectue la même vérification. »

« Je crois que je comprends maintenant. »

« Excellent. »

« Et que signifie 'Exception' dans l'instruction catch ? »

"Toutes les exceptions sont des classes qui héritent de la classe Exception. Nous pouvons attraper une exception particulière en spécifiant la classe de l'exception dans le bloc catch, ou nous pouvons attraper toutes les exceptions en spécifiant leur classe parente commune : Exception. Ensuite, nous pouvons obtenir toutes les informations nécessaires sur l'erreur à partir de la variable e (qui stocke une référence à l'objet d'exception). »

« Cool ! Si des exceptions différentes se produisent dans ma méthode, est-ce que je peux les traiter différemment ? »

« Tu peux, et tu dois le faire. Tu peux le faire comme ceci : »

Exemple :
public class ExceptionExample2
{
    public static void main(String[] args)
    {
        System.out.println("Program starts");

        try
        {
            System.out.println("Before calling method1");
            method1();
            System.out.println("After calling method1. This will never be shown");
        }
        catch (NullPointerException e)
        {
           System.out.println("Null reference. Exception has been caught");
        }
        catch (ArithmeticException e)
        {
            System.out.println("Division by zero. Exception has been caught");
        }
        catch (Exception e)
        {
            System.out.println("Any other errors. Exception has been caught");
        }

        System.out.println("Program is still running");
    }

    public static void method1()
    {
        int a = 100;
        int b = 0;
        System.out.println(a / b);
    }
}

« Le bloc try peut être associé à plusieurs blocs catch, et chacun capturera les types d'exception spécifiés. »

« Je crois que je comprends. Je ne peux pas encore l'écrire moi-même, mais si je trouve ça dans mon code, ça ne me fera pas peur. »