JavaRush /Java-Blog /Random-DE /Ausnahmen in Java: Abfangen und Behandeln

Ausnahmen in Java: Abfangen und Behandeln

Veröffentlicht in der Gruppe Random-DE
Hallo! Ich sage es Ihnen nur ungern, aber ein großer Teil der Arbeit eines Programmierers besteht darin, mit Fehlern umzugehen. Und am häufigsten - mit ihren eigenen. Es ist einfach so, dass es keine Menschen gibt, die keine Fehler machen. Und solche Programme gibt es auch nicht. Bei der Bearbeitung eines Fehlers kommt es natürlich vor allem darauf an, seine Ursache zu verstehen. Und dafür kann es im Programm eine ganze Reihe von Gründen geben. Irgendwann standen die Entwickler von Java vor der Frage: Was tun mit diesen potenziellen Fehlern in Programmen? Sie vollständig zu vermeiden ist unrealistisch. Programmierer können etwas schreiben, das man sich nicht einmal vorstellen kann :) Das bedeutet, dass es notwendig ist, in die Sprache einen Mechanismus zum Umgang mit Fehlern einzubauen. Mit anderen Worten: Wenn im Programm ein Fehler aufgetreten ist, ist für die weitere Arbeit ein Skript erforderlich. Was genau soll das Programm tun, wenn ein Fehler auftritt? Heute werden wir diesen Mechanismus kennenlernen. Und es heißt „Ausnahmen .

Was ist eine Ausnahme in Java?

Eine Ausnahme bilden außergewöhnliche, ungeplante Situationen, die während der Ausführung des Programms eingetreten sind. Es kann viele Beispiele für Ausnahmen in Java geben. Sie haben beispielsweise einen Code geschrieben, der Text aus einer Datei liest und die erste Zeile auf der Konsole anzeigt.
public class Main {

   public static void main(String[] args) throws IOException {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   }
}
Aber eine solche Datei existiert nicht! Das Ergebnis des Programms wird eine Ausnahme sein - FileNotFoundException. Abschluss:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Jede Ausnahme wird in Java durch eine separate Klasse dargestellt. Alle Ausnahmeklassen stammen von einem gemeinsamen „Vorfahren“ – der Elternklasse Throwable. Der Name der Ausnahmeklasse gibt in der Regel kurz den Grund für ihr Auftreten wieder:
  • FileNotFoundException(die Datei wurde nicht gefunden)
  • ArithmeticException(Ausnahme bei der Durchführung einer mathematischen Operation)
  • ArrayIndexOutOfBoundsException(Die Nummer der Array-Zelle wird über ihre Länge hinaus angegeben.) Wenn Sie beispielsweise versuchen, das Zellenarray[23] für ein Array-Array der Länge 10 an die Konsole auszugeben.
Es gibt fast 400 solcher Klassen in Java! Warum so viele? Gerade um es Programmierern komfortabler zu machen, damit zu arbeiten. Stellen Sie sich vor: Sie haben ein Programm geschrieben, und wenn es ausgeführt wird, löst es eine Ausnahme aus, die so aussieht:
Exception in thread "main"
Äh-äh :/ Nichts ist klar. Um welche Art von Fehler es sich handelt und woher er kommt, ist unklar. Es gibt keine nützlichen Informationen. Aber dank einer solchen Klassenvielfalt erhält der Programmierer die Hauptsache für sich selbst – die Art des Fehlers und seine wahrscheinliche Ursache, die im Namen der Klasse enthalten ist. Schließlich sieht es in der Konsole ganz anders aus:
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Es wird sofort klar, wo das Problem liegen könnte und „in welche Richtung man graben muss“, um das Problem zu lösen! Ausnahmen sind wie alle Instanzen von Klassen Objekte.

Ausnahmen abfangen und behandeln

Um mit Ausnahmen in Java zu arbeiten, gibt es spezielle Codeblöcke: try, catchund finally. Ausnahmen: Abfangen und Verarbeiten – 2Der Code, in dem der Programmierer das Auftreten von Ausnahmen erwartet, wird in einen Block eingefügt try. Dies bedeutet nicht, dass an dieser Stelle zwangsläufig eine Ausnahme auftritt. Das bedeutet, dass es dort passieren kann und der Programmierer sich dessen bewusst ist. Die Art des Fehlers, den Sie erwarten, wird in einem Block catch(„catch“) platziert. Hier wird auch der gesamte Code platziert, der ausgeführt werden muss, wenn eine Ausnahme auftritt. Hier ist ein Beispiel:
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Fehler Datei nicht gefunden!");
   }
}
Abschluss:

Ошибка! Файл не найден!
Wir gliedern unseren Code in zwei Blöcke. Im ersten Block erwarten wir, dass der Fehler „Datei nicht gefunden“ auftreten kann. Das ist ein Block try. Im zweiten Schritt teilen wir dem Programm mit, was zu tun ist, wenn ein Fehler auftritt. Darüber hinaus gibt es eine bestimmte Art von Fehler – FileNotFoundException. Wenn wir catchin den Blockklammern eine andere Ausnahmeklasse übergeben, wird diese nicht abgefangen.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (ArithmeticException e) {

       System.out.println("Fehler Datei nicht gefunden!");
   }
}
Abschluss:

Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (Системе не удается найти указанный путь)
Der Code im Block catchhat nicht funktioniert, weil wir diesen Block so „konfiguriert“ haben, dass er abfängt ArithmeticException, und der Code im Block tryeinen anderen Typ ausgeworfen hat – FileNotFoundException. Wir haben kein Skript für geschrieben FileNotFoundException, daher zeigte das Programm in der Konsole die Informationen an, die standardmäßig für angezeigt werden FileNotFoundException. Hier müssen Sie auf 3 Dinge achten. Erste. Sobald in einer Codezeile eines Try-Blocks eine Ausnahme auftritt, wird der darauf folgende Code nicht mehr ausgeführt. Die Ausführung des Programms wird sofort zum Block „springen“ catch. Zum Beispiel:
public static void main(String[] args) {
   try {
       System.out.println(„Dividiere eine Zahl durch Null“);
       System.out.println(366/0);//Diese Codezeile löst eine Ausnahme aus

       System.out.println("Das");
       System.out.println("Code");
       System.out.println("Nicht");
       System.out.println("Wille");
       System.out.println("Erledigt!");

   } catch (ArithmeticException e) {

       System.out.println(„Das Programm ist zum Catch-Block gesprungen!“);
       System.out.println(„Fehler! Man kann nicht durch Null dividieren!“);
   }
}
Abschluss:

Делим число на ноль 
Программа перепрыгнула в блок catch! 
Ошибка! Нельзя делить на ноль! 
Im Block tryin der zweiten Zeile haben wir versucht, eine Zahl durch 0 zu dividieren, was zu einer Ausnahme führte ArithmeticException. Danach trywerden die Zeilen 6-10 des Blocks nicht mehr ausgeführt. Wie gesagt, das Programm begann sofort mit der Ausführung des Blocks catch. Zweite. Es können mehrere Blöcke vorhanden sein catch. Wenn der Code in einem Block trynicht nur eine, sondern mehrere Arten von Ausnahmen auslösen kann, können Sie für jede davon einen eigenen Block schreiben catch.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       System.out.println(366/0);
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {

       System.out.println("Fehler Datei nicht gefunden!");

   } catch (ArithmeticException e) {

       System.out.println(„Fehler! Division durch 0!“);

   }
}
In diesem Beispiel haben wir zwei Blöcke geschrieben catch. Wenn , im Block tryvorkommt FileNotFoundException, wird der erste Block ausgeführt catch. In diesem Fall ArithmeticExceptionwird der zweite ausgeführt. Sie können mindestens 50 Blöcke schreiben catch. Aber natürlich ist es besser, keinen Code zu schreiben, der 50 verschiedene Arten von Fehlern auslösen kann :) Drittens. Woher wissen Sie, welche Ausnahmen Ihr Code auslösen könnte? Natürlich kann man einiges erraten, aber es ist unmöglich, alles im Kopf zu behalten. Daher kennt der Java-Compiler die häufigsten Ausnahmen und weiß, in welchen Situationen sie auftreten können. Wenn Sie beispielsweise Code geschrieben haben und der Compiler weiß, dass während seines Betriebs zwei Arten von Ausnahmen auftreten können, wird Ihr Code erst kompiliert, wenn Sie diese behandelt haben. Wir werden unten Beispiele dafür sehen. Nun zur Ausnahmebehandlung. Es gibt zwei Möglichkeiten, sie zu verarbeiten. Den ersten haben wir bereits kennengelernt – die Methode kann die Ausnahme selbstständig im Block behandeln catch(). Es gibt eine zweite Option: Die Methode kann eine Ausnahme im Aufrufstapel auslösen. Was bedeutet das? In unserer Klasse haben wir beispielsweise eine Methode – dieselbe printFirstString()–, die eine Datei liest und deren erste Zeile auf der Konsole anzeigt:
public static void printFirstString(String filePath) {

   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Derzeit lässt sich unser Code nicht kompilieren, da er unbehandelte Ausnahmen aufweist. In Zeile 1 geben Sie den Pfad zur Datei an. Der Compiler weiß, dass solcher Code leicht zu . führen kann FileNotFoundException. In Zeile 3 lesen Sie Text aus der Datei. Bei diesem Vorgang kann es leicht zu IOExceptioneinem Fehler bei der Eingabe-Ausgabe (Input-Output) kommen. Jetzt sagt Ihnen der Compiler: „Alter, ich werde diesen Code nicht genehmigen oder kompilieren, bis Sie mir sagen, was ich tun soll, wenn eine dieser Ausnahmen auftritt.“ Und basierend auf dem Code, den Sie geschrieben haben, können sie definitiv passieren!“ . Es gibt keinen Weg dorthin, Sie müssen beides verarbeiten! Die erste Verarbeitungsoption ist uns bereits bekannt: Wir müssen unseren Code in einem Block platzieren tryund zwei Blöcke hinzufügen catch:
public static void printFirstString(String filePath) {

   try {
       BufferedReader reader = new BufferedReader(new FileReader(filePath));
       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Fehler Datei nicht gefunden!");
       e.printStackTrace();
   } catch (IOException e) {
       System.out.println(„Fehler beim Ein-/Ausgeben von Daten aus der Datei!“);
       e.printStackTrace();
   }
}
Dies ist jedoch nicht die einzige Option. Wir können das Schreiben eines Skripts für den Fehler innerhalb der Methode vermeiden und die Ausnahme einfach nach oben werfen. Dies geschieht mit dem Schlüsselwort throws, das in der Methodendeklaration geschrieben wird:
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
   BufferedReader reader = new BufferedReader(new FileReader(filePath));
   String firstString = reader.readLine();
   System.out.println(firstString);
}
Nach dem Wort throwslisten wir, durch Kommas getrennt, alle Arten von Ausnahmen auf, die diese Methode während des Betriebs auslösen kann. Warum wird das gemacht? Wenn nun jemand im Programm die Methode aufrufen möchte printFirstString(), muss er die Ausnahmebehandlung selbst implementieren. Beispielsweise hat einer Ihrer Kollegen in einem anderen Teil des Programms eine Methode geschrieben, in der Ihre Methode aufgerufen wird printFirstString():
public static void yourColleagueMethod() {

   //...die Methode Ihres Kollegen bewirkt etwas

   //...und ruft in einem Moment Ihre printFirstString()-Methode mit der benötigten Datei auf
   printFirstString(„C:\\Benutzer\\Eugene\\Desktop\\testFile.txt“);
}
Fehler, der Code lässt sich nicht kompilieren! Wir haben in der Methode printFirstString()kein Fehlerbehandlungsskript geschrieben . Daher liegt die Aufgabe auf den Schultern derjenigen, die diese Methode anwenden. Das heißt, die Methode yourColleagueMethod()hat jetzt die gleichen zwei Optionen: Sie muss entweder beide Ausnahmen verarbeiten, die mit zu ihr „geflogen“ sind try-catch, oder sie weiterleiten.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
   //...die Methode macht etwas

   //...und ruft in einem Moment Ihre printFirstString()-Methode mit der benötigten Datei auf
   printFirstString(„C:\\Benutzer\\Eugene\\Desktop\\testFile.txt“);
}
Im zweiten Fall fällt die Verarbeitung auf die Schultern der nächsten Methode auf dem Stapel – derjenigen, die aufruft yourColleagueMethod(). Aus diesem Grund wird ein solcher Mechanismus als „Auslösen einer Ausnahme nach oben“ oder „Übergeben nach oben“ bezeichnet. Wenn Sie mit Ausnahmen auslösen throws, wird der Code kompiliert. In diesem Moment scheint der Compiler zu sagen: „Okay, okay. Ihr Code enthält eine Reihe potenzieller Ausnahmen, aber ich werde ihn trotzdem kompilieren. Wir werden auf dieses Gespräch zurückkommen!“ Und wenn Sie irgendwo im Programm eine Methode aufrufen, die ihre Ausnahmen nicht behandelt hat, erfüllt der Compiler sein Versprechen und erinnert Sie erneut daran. Abschließend sprechen wir über den Block finally(entschuldigen Sie das Wortspiel). Dies ist der letzte Teil des Ausnahmebehandlungs-Triumvirats try-catch-finally. Seine Besonderheit besteht darin, dass es in jedem Programmbetriebsszenario ausgeführt werden kann.
public static void main(String[] args) throws IOException {
   try {
       BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       System.out.println("Fehler Datei nicht gefunden!");
       e.printStackTrace();
   } finally {
       System.out.println(„Und hier ist der letzte Block!“);
   }
}
In diesem Beispiel wird der Code innerhalb des Blocks finallyin beiden Fällen ausgeführt. Wenn der Code im Block tryvollständig ausgeführt wird und keine Ausnahme auslöst, wird der Block am Ende ausgelöst finally. Wenn der darin enthaltene Code tryunterbrochen wird und das Programm zu dem Block springt catch, wird der Block nach der Ausführung des darin enthaltenen Codes catchweiterhin ausgewählt finally. Warum wird es benötigt? Sein Hauptzweck besteht darin, den erforderlichen Teil des Codes auszuführen; der Teil, der unabhängig von den Umständen abgeschlossen werden muss. Beispielsweise werden dadurch häufig einige vom Programm verwendete Ressourcen freigegeben. In unserem Code öffnen wir einen Stream, um Informationen aus einer Datei zu lesen und an eine BufferedReader. Unseres readermuss geschlossen und Ressourcen freigesetzt werden. Dies muss auf jeden Fall erfolgen: Es spielt keine Rolle, ob das Programm wie erwartet funktioniert oder eine Ausnahme auslöst. Es ist praktisch, dies in einem Block zu tun finally:
public static void main(String[] args) throws IOException {

   BufferedReader reader = null;
   try {
       reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));

       String firstString = reader.readLine();
       System.out.println(firstString);
   } catch (FileNotFoundException e) {
       e.printStackTrace();
   } finally {
       System.out.println(„Und hier ist der letzte Block!“);
       if (reader != null) {
           reader.close();
       }
   }
}
Jetzt sind wir absolut sicher, dass wir uns um die belegten Ressourcen gekümmert haben, unabhängig davon, was passiert, während das Programm läuft :) Das ist noch nicht alles, was Sie über Ausnahmen wissen müssen. Die Fehlerbehandlung ist ein sehr wichtiges Thema in der Programmierung: Mehr als ein Artikel ist diesem Thema gewidmet. In der nächsten Lektion erfahren wir, welche Arten von Ausnahmen es gibt und wie Sie Ihre eigene Ausnahme erstellen :) Wir sehen uns dort!
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION