"Hallo, Amigo. We gaan een zeer interessante les hebben vandaag. Ik ga je vertellen over uitzonderingen. Uitzonderingen zijn een speciaal mechanisme waarmee we fouten in het programma kunnen afhandelen. Hier zijn enkele voorbeelden van fouten die kunnen optreden bij een programma:

1. Het programma kan proberen een bestand te schrijven als de harde schijf helemaal vol is.

2. Het programma kan proberen een methode aan te roepen op een variabele die een null-referentie opslaat.

3. Het programma probeert mogelijk een getal door 0 te delen."

Al deze acties resulteren in fouten. Meestal is het resultaat dat het programma onmiddellijk wordt beëindigd, aangezien het in dit geval geen zin heeft om door te gaan met het uitvoeren van code.

"Waarom?"

"Heeft het zin om aan een wiel te blijven draaien als de auto van de weg is geraakt en van een klif valt?"

"Moet het programma dan stoppen?"

"Ja. Tenminste, dit is wat vroeger gebeurde. Elke fout zorgde ervoor dat het programma stopte."

"Dat is een heel slimme aanpak."

"Maar zou het niet beter zijn om te proberen het programma te blijven uitvoeren?"

"Ja. Stel dat u een enorme hoeveelheid tekst in Word hebt getypt en deze hebt opgeslagen. Wat als de opslagbewerking mislukt, maar het programma u doet geloven dat alles in orde is? En u blijft typen. Dat zou stom zijn, nietwaar? Het?"

"Ja."

"Toen kwamen programmeurs met een interessante oplossing: elke functie zou de status van zijn werk retourneren. 0 betekende dat het werkte zoals verwacht. Elke andere waarde zou betekenen dat er een fout was opgetreden en de geretourneerde waarde was een foutcode."

“Die aanpak heeft echter ook zijn tekortkomingen. Na elke (!) functieaanroep moet je de returncode(nummer) controleren. Dat is allereerst onhandig: de foutafhandelingscode wordt zelden uitgevoerd maar moet wel worden meegenomen overal. Ten tweede geven functies vaak verschillende waarden terug – wat moet je ermee doen?"

'Juist. Daar heb ik ook over nagedacht.'

"Toen brak er een mooie toekomst aan in de vorm van uitzonderingen en een foutafhandelingsmechanisme. Zo werkt het:

1. Wanneer er een fout optreedt, maakt de Java-machine een speciaal object – een uitzondering – waarin alle foutinformatie wordt opgeslagen. Er zijn verschillende uitzonderingen voor verschillende fouten.

2. Een uitzondering zorgt ervoor dat het programma onmiddellijk de huidige functie verlaat, en de volgende functie, enzovoort, totdat het de hoofdmethode verlaat. Dan stopt het programma. Programmeurs kunnen ook zeggen dat de Java-machine 'de call-stack afwikkelt'."

'Maar je zei dat het programma niet altijd stopt.'

"Ja, want er is een manier om een ​​uitzondering op te vangen. We kunnen speciale code op de juiste plaats schrijven om de uitzonderingen op te vangen waar we om geven en om er iets mee te doen. Dit zijn belangrijke dingen."

"Om ons hierbij te helpen, is er een speciale try-catch constructie. Zo werkt het:"

Voorbeeld van een programma dat een uitzondering opvangt (delen door 0) en blijft werken.
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);
    }
}
Schermuitvoer:
Program starts
Before method1 calling
Exception has been caught
Program is still running

"Maar waarom wordt 'Na het aanroepen van methode 1. Dit wordt nooit getoond' niet weergegeven op het scherm?"

"Ik ben blij dat je het vraagt. In regel 25 delen we door 0, wat leidt tot een fout - een uitzondering. De Java-machine maakt een ArithmeticException- object met informatie over de fout. Het object is de uitzondering."

"De uitzondering doet zich voor binnen de method1methode. Dit zorgt ervoor dat de methode onmiddellijk wordt beëindigd. Het zou ervoor zorgen dat de hoofdmethode wordt beëindigd als het try-catch- blok er niet was."

"Als er een uitzondering optreedt binnen een try- blok, wordt deze opgevangen in het catch- blok. De rest van de code in het try-blok wordt niet uitgevoerd. In plaats daarvan wordt het catch- blok uitgevoerd. "

"Ik snap het niet."

"Met andere woorden, de code werkt als volgt:

1. Als er een uitzondering optreedt binnen een try- blok, wordt de uitvoering van de code stopgezet op de plaats waar de uitzondering zich voordeed en begint het catch- blok te worden uitgevoerd.

2. Als er geen uitzondering optreedt, wordt het try-blok tot het einde uitgevoerd en wordt het catch- blok niet uitgevoerd. "

"Huh?"

"Stel je voor dat we na elke methodeaanroep controleren of de methode normaal terugkeerde of abrupt werd beëindigd als gevolg van een uitzondering. Als er een uitzondering is, gaan we verder met het uitvoeren van het catch-blok (als er een is) om de uitzondering op te vangen. Als er geen catch-blok is, beëindigen we de huidige methode en voert de methode die ons heeft aangeroepen dezelfde controle uit."

"Ik denk dat ik het nu heb."

"Uitstekend."

"Wat betekent 'Uitzondering' in de catch-instructie?"

" Alle exceptions zijn klassen die de Exception-klasse erven. We kunnen een bepaalde exception opvangen door de exception-klasse in het catch- blok op te geven, of we kunnen alle exceptions opvangen door hun gemeenschappelijke bovenliggende klasse op te geven – Exception. Dan kunnen we alle noodzakelijke fouten krijgen informatie van de variabele e (het slaat een verwijzing naar het uitzonderingsobject op)."

"Cool! Als er verschillende uitzonderingen voorkomen in mijn methode, kan ik ze dan anders verwerken?"

"Het kan niet alleen, het moet ook. Je kunt dat zo doen:"

Voorbeeld:
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);
    }
}

"Het try- blok kan worden gecombineerd met verschillende catch- blokken, die elk de gespecificeerde soorten uitzonderingen opvangen."

"Ik denk dat ik het begrijp. Ik kan dit zelf nog niet schrijven, maar als ik het in code tegenkom, schrik ik niet."