1. Ausnahmen

>

Endlich dachten Programmierer darüber nach, die Fehlerbehandlung zu standardisieren und zu automatisieren. Dies geschah, als Ausnahmen erfunden wurden. Mittlerweile behandelt der Ausnahmemechanismus 80 % der Ausnahmesituationen.

Wenn sich ein Wissenschaftler Ausnahmen einfallen ließ, handelte es sich wahrscheinlich um das Thema seiner Doktorarbeit. Wenn ein Programmierer darauf gekommen ist, dann hat ihm vielleicht ein Kollege freundlich auf die Schulter geklopft: „Scheint okay, Bruder.“

Wenn in einem Java-Programm ein Fehler auftritt, beispielsweise eine Division durch 0, passieren einige wunderbare Dinge:

Schritt eins

Es wird ein spezielles Ausnahmeobjekt erstellt, das Informationen über den aufgetretenen Fehler enthält.

Alles in Java ist ein Objekt, und Ausnahmen sind keine Ausnahmen 🙂 Ausnahmeobjekte haben ihre eigenen Klassen, und das einzige, was sie von gewöhnlichen Klassen unterscheidet, ist, dass sie die ThrowableKlasse erben.

Schritt zwei

Das Ausnahmeobjekt wird „geworfen“. Vielleicht könnte die Formulierung hier besser sein. „Eine Ausnahme auslösen“ ähnelt eher dem Auslösen eines Feueralarms oder dem Ertönen eines „DEFCON 1“-Alarms.

Wenn eine Ausnahme an die Java-Maschine geworfen wird, wird der normale Betrieb des Programms gestoppt und „Notfallprotokolle“ beginnen.

Schritt drei

Die Methode, in der die Ausnahme ausgelöst wurde, wird sofort beendet. Die Ausnahme wird an die aufrufende Methode übergeben, die ebenfalls sofort beendet wird. Und so weiter in der Kette, bis die mainMethode beendet wird. Wenn die mainMethode beendet wird, endet auch das Programm.

Beispiel:

Code Konsolenausgabe
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

In Zeile 20 tritt eine Ausnahme auf: Division durch 0. Die Java-Maschine erstellt sofort eine Ausnahme – ein ArithmeticExceptionObjekt und „wirft“ es an die Methode.

Die divide()Methode endet sofort, sodass wir nie die Zeichenfolge sehen: Es ist nichts Schlimmes passiert: 0. Das Programm kehrt zur endTheWorld()Methode zurück und die Situation wiederholt sich: Es gibt eine nicht behandelte Ausnahme im System, was bedeutet, dass die endTheWorld()Methode ebenfalls abnormal beendet wird. Dann wird die mainMethode beendet und das Programm stoppt.

Welchen Zweck haben diese Ausnahmen? Nun, Sie können Ihren eigenen Code schreiben, um bestimmte Arten von Ausnahmen abzufangen, und Ihre eigene Logik schreiben, um Ausnahmesituationen zu bewältigen.


2. Ausnahmen abfangen:try-catch

Java verfügt über einen Mechanismus zum Abfangen von Ausnahmen, mit dem Sie diese abnormale Beendigung von Methoden stoppen können. Es sieht aus wie das:

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

Dieses Konstrukt wird als Block bezeichnet try-catch.

Code, in dem Ausnahmen auftreten können, wird in geschweifte Klammern eingeschlossen, denen das Wort vorangestellt ist try.

Nach den geschweiften Klammern steht das catchSchlüsselwort und in Klammern die Deklaration einer Ausnahmevariablen . Darauf folgen geschweifte Klammern, die den Code umschließen, der ausgeführt werden soll, wenn eine Ausnahme des angegebenen Typs auftritt .

Wenn während der Ausführung des „ Primärcodes “ keine Ausnahmen ausgelöst werden, wird der Code im Catch-Block nicht ausgeführt. Wenn eine Ausnahme auftritt, wird dies der Fall sein (wenn der Typ der ausgelösten Ausnahme mit dem Typ der Variablen in Klammern übereinstimmt).

Beispiel:

Code Konsolenausgabe
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. Mehrere catchBlöcke

Mehrere Fangblöcke

Theoretisch können in einem Codeblock alle möglichen Ausnahmen ausgelöst werden. Einige werden Sie auf die eine Art und Weise angehen wollen, andere auf eine andere Art und wieder andere werden Sie beschließen, überhaupt nicht damit umzugehen.

Java-Entwickler haben beschlossen, Ihnen zu helfen und Sie nicht nur einen, sondern viele catchBlöcke nach dem tryBlock schreiben zu lassen.

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
}

Beispiel:

Code Konsolenausgabe
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. Reihenfolge der catchBlöcke

Ausnahmen, die in einem tryBlock auftreten, können nur von einem einzelnen Block abgefangen werden catch. Es kann keine Ausnahmebehandlungssituation geben , in der der Code aus mehreren catchBlöcken ausgeführt wird.

Aber die Reihenfolge der Blöcke ist wichtig.

Es kann vorkommen, dass eine Ausnahme von mehreren Blöcken abgefangen wird. Wenn dies der Fall ist, wird die Ausnahme von dem Catch- Block abgefangen, der zuerst kommt (der dem tryBlock am nächsten liegt).

Wie kann es passieren, dass mehrere Catch-Blöcke dieselbe Ausnahme abfangen können?

Alle Ausnahmen gehören zu einer einzigen Vererbungshierarchie – siehe Diagramm.

Ausnahmehierarchie

Ein ArithmeticExceptionObjekt kann einer Variablen vom Typ ArithmeticExceptionoder einer ihrer Vorgängerklassen zugewiesen werden: RuntimeException , Exceptionund Throwable– siehe Diagramm.

Wir werden in Level 21 mehr über Vererbung und Vorfahrenklassen sprechen.

Dieser Code lässt sich problemlos kompilieren:

Vorteile einer Vererbung:
ArithmeticException ae    = new ArithmeticException();
RuntimeException runtime  = new ArithmeticException();
Exception exception       = new ArithmeticException();
Throwable trwbl           = new ArithmeticException();

Sie können also einen ArithmeticExceptionmit jedem der 4 catchoben genannten Blöcke erreichen.

Beispiel 1:

Code Konsolenausgabe
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 diesem Beispiel kann das sowohl von den Blöcken als auch ArithmeticExceptionabgefangen werden . Es wird von dem Block abgefangen, der dem Block am nächsten ist – dem ersten Block.catch (Exception e)catch (ArithmeticException e)trycatch

Um Überraschungen zu vermeiden, ist es am besten, catchBlöcke, die nahezu jede Ausnahme abfangen können, am Ende der Blockliste zu platzieren catch.

Der ThrowableTyp ist im Allgemeinen in der Lage, jede mögliche Ausnahme in Java abzufangen . Wenn Sie es in den ersten catchBlock einfügen, wird der Code nicht kompiliert, da der Compiler weiß, dass es nicht erreichbare Codeblöcke gibt.