1. Uitzonderingen

>

Uiteindelijk dachten programmeurs aan het standaardiseren en automatiseren van foutafhandeling. Dit gebeurde toen uitzonderingen werden uitgevonden. Nu behandelt het uitzonderingsmechanisme 80% van de uitzonderlijke situaties.

Als een geleerde uitzonderingen bedacht, was dat waarschijnlijk het onderwerp van zijn of haar proefschrift. Als een programmeur het heeft bedacht, heeft hij misschien een vriendelijk schouderklopje gekregen van een collega: "Lijkt goed, man."

Wanneer er een fout optreedt in een Java-programma, zoals delen door 0, gebeuren er enkele wonderlijke dingen:

Stap een

Er wordt een speciaal uitzonderingsobject gemaakt dat informatie bevat over de opgetreden fout.

Alles in Java is een object, en uitzonderingen zijn geen uitzonderingen 🙂 Uitzonderingsobjecten hebben hun eigen klassen en het enige dat ze onderscheidt van gewone klassen is dat ze de Throwableklasse erven.

Stap twee

Het uitzonderingsobject wordt "gegooid". Misschien kan de formulering hier beter. "Een uitzondering genereren" lijkt meer op het activeren van een brandalarm of het laten klinken van een "DEFCON 1"-waarschuwing.

Wanneer een uitzondering naar de Java-machine wordt gegenereerd, stopt de normale werking van het programma en beginnen "noodprotocollen".

Stap drie

De methode waarin de uitzondering is gegenereerd, wordt onmiddellijk afgesloten. De uitzondering wordt doorgegeven aan de aanroepende methode, die ook onmiddellijk wordt afgesloten. En zo verder in de keten totdat de mainmethode wordt afgesloten. Wanneer de mainmethode eindigt, doet het programma dat ook.

Voorbeeld:

Code Console-uitvoer
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Your attention, please! Preparing for the end of the world");
      endTheWorld();
      System.out.println("The world ended successfully");
   }

   public static void endTheWorld()
   {
      System.out.println("We're doing something important");
      doSomeWork(0);
      System.out.println("Everything is working well");
   }

   public static void doSomeWork(int n)
   {
      System.out.println("Nothing terrible will happen: " + n);
      System.out.println(2 / n);
      System.out.println("Nothing terrible happened: " + n);
   }
}
Your attention, please! Preparing for the end of the world
We're doing something important
Nothing terrible will happen: 0

Er doet zich een uitzondering voor op regel 20: deling door 0. De Java-machine maakt onmiddellijk een uitzondering - een ArithmeticExceptionobject - en "gooit" deze naar de methode.

De divide()methode eindigt onmiddellijk, dus we zien nooit de string: Er is niets ergs gebeurd: 0. Het programma keert terug naar de endTheWorld()methode en de situatie herhaalt zich: er is een onverwerkte uitzondering in het systeem, wat betekent dat de endTheWorld()methode ook abnormaal wordt beëindigd. Dan maineindigt de methode en stopt het programma.

Wat is het doel van deze uitzonderingen? Welnu, u kunt uw eigen code schrijven om bepaalde soorten uitzonderingen op te vangen en uw eigen logica schrijven om uitzonderlijke situaties aan te pakken.


2. Uitzonderingen vangen:try-catch

Java heeft een mechanisme voor het opvangen van uitzonderingen waarmee u deze abnormale beëindiging van methoden kunt stoppen. Het ziet er zo uit:

try
{
   // Code where an exception might occur
}
catch(ExceptionType name)
{
   // Exception handling code
}

Deze constructie wordt een try-catchblok genoemd.

Code waar uitzonderingen op kunnen voorkomen, staat tussen accolades, voorafgegaan door het woord try.

Na de accolades hebben we het catchsleutelwoord en, tussen haakjes, de declaratie van een uitzonderingsvariabele . Dit wordt gevolgd door accolades die de uit te voeren code omsluiten als zich een uitzondering van het opgegeven type voordoet .

Als er geen uitzonderingen worden gegenereerd tijdens de uitvoering van de " primaire code ", wordt de code in het catch-blok niet uitgevoerd. Als er een uitzondering optreedt, is dat het geval (als het type van de gegenereerde uitzondering hetzelfde is als het type van de variabele tussen haakjes).

Voorbeeld:

Code Console-uitvoer
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Hadron Collider launched");

      try
      {
         launchHadronCollider(1);
         launchHadronCollider(0);
      }
      catch(Exception e)
      {
         System.out.println("Error! Caught an exception");
         System.out.println("The planet was sucked into a black hole!");
      }

      System.out.println("The Hadron Collider stopped");
   }

   public static void launchHadronCollider(int n)
   {
      System.out.println("Everything is working well: " + n);
      System.out.println(2/n);
      System.out.println("There are no problems: " + n);
   }
}
Hadron Collider launched
Everything is working fine: 1
2
There are no problems: 1
Everything is working fine: 0
Error! Caught an exception
The planet has been sucked into a black hole!
The Hadron Collider is stopped


3. Meerdere catchblokken

Meerdere vangblokken

In theorie kunnen allerlei uitzonderingen in een codeblok worden gegooid. Sommige zul je op de ene manier willen behandelen, andere op een andere manier, en weer andere zul je besluiten helemaal niet aan te pakken.

Java-ontwikkelaars besloten je te helpen en lieten je niet één maar vele catchblokken achter het tryblok schrijven.

try
{
   // Code where an exception might occur
}
catch (ExceptionType1 name1)
{
   // Code for handling ExceptionType1
}
catch (ExceptionType2 name2)
{
   // Code for handling ExceptionType2
}
   catch (ExceptionType3 name3)
{
   // Code for handling ExceptionType3
}

Voorbeeld:

Code Console-uitvoer
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Start of main method");
      try
      {
         calculate(0);
      }
      catch (ArithmeticException e)
      {
         System.out.println("Division by 0");
      }
      catch(Exception e)
      {
         System.out.println("Caught some kind of exception");
      }

      System.out.println("End of main method");
   }

   public static void calculate(int n)
   {
      System.out.println("Start of calculate method: " + n);
      System.out.println(2/n);
      System.out.println("End of calculate method: " + n);
   }
}
Start of main method
Start of calculate method: 0
Division by 0
End of main method


4. Volgorde van catchblokken

Uitzonderingen die in een tryblok voorkomen, kunnen alleen door een enkel blok worden opgevangen catch. U kunt geen uitzonderingsafhandelingssituatie hebben waarbij de code van meerdere catchblokken wordt uitgevoerd.

Maar de volgorde van de blokken is belangrijk.

U kunt een situatie hebben waarin een uitzondering kan worden opgevangen door meerdere blokken. Als dat het geval is, wordt de uitzondering opgevangen door het catch- blok dat het eerst komt (het dichtst bij het tryblok).

Hoe kun je een situatie hebben waarin meerdere catch-blokken dezelfde uitzondering kunnen opvangen?

Alle uitzonderingen behoren tot een enkele overervingshiërarchie — zie het diagram.

Uitzonderingshiërarchie

Een ArithmeticExceptionobject kan worden toegewezen aan een variabele waarvan het type ArithmeticExceptionof een van zijn voorouderklassen is: RuntimeException , Exceptionen Throwable- zie het diagram.

We zullen meer praten over overerving en voorouderklassen in niveau 21.

Deze code zal prima compileren:

Voordelen van overerving:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

Je kunt dus een vangen ArithmeticExceptionmet een van de 4 catchbovenstaande blokken.

Voorbeeld 1:

Code Console-uitvoer
class Solution
{
   public static void main(String[] args)
   {
      System.out.println("Start of main method");
      try
      {
         calculate(0);
      }
      catch(ArithmeticException e)
      {
         System.out.println("Division by 0");
      }
      catch(Exception e)
      {
         System.out.println("Caught some kind of exception");
      }

      System.out.println("End of main method");
   }

   public static void calculate(int n)
   {
      System.out.println("Start of calculate method: " + n);
      System.out.println(2/n);
      System.out.println("End of calculate method: " + n);
   }
}
Start of main method
Start of calculate method: 0
Division by 0
End of main method

In dit voorbeeld ArithmeticExceptionkan de worden opgevangen door zowel de catch (Exception e)als catch (ArithmeticException e)blokken. Het wordt opgevangen door het blok dat zich het dichtst bij het tryblok bevindt - het eerste catchblok.

catchOm verrassingen te voorkomen, is het het beste om blokken die bijna elke uitzondering kunnen opvangen aan het einde van de lijst met blokken te plaatsen .catch

Het Throwabletype is over het algemeen in staat om elke mogelijke uitzondering in Java op te vangen . Als je het in het eerste catchblok plaatst, zal de code niet compileren, omdat de compiler weet dat er onbereikbare codeblokken zijn.