1. Arten von Ausnahmen
Alle Ausnahmen sind in 4 Typen unterteilt, bei denen es sich tatsächlich um Klassen handelt, die sich gegenseitig erben.
Throwable
Klasse
Die Basisklasse für alle Ausnahmen ist die Throwable
Klasse. Die Throwable
Klasse enthält den Code, der den aktuellen Aufrufstapel (Stacktrace der aktuellen Methode) in ein Array schreibt. Was ein Stacktrace ist, erfahren wir etwas später.
Der Throw- Operator kann nur ein Objekt akzeptieren, das von der Throwable
Klasse abgeleitet ist. Und obwohl man theoretisch Code wie schreiben kann throw new Throwable();
, macht das normalerweise niemand. Der Hauptzweck der Throwable
Klasse besteht darin, für alle Ausnahmen eine einzige übergeordnete Klasse zu haben.
Error
Klasse
Die nächste Ausnahmeklasse ist die Error
Klasse, die die Klasse direkt erbt Throwable
. Die Java-Maschine erstellt Objekte der Error
Klasse (und ihrer Nachkommen) , wenn schwerwiegende Probleme aufgetreten sind . Zum Beispiel eine Hardwarestörung, unzureichender Speicher usw.
Normalerweise können Sie als Programmierer nichts tun , wenn ein solcher Fehler (die Art, für die ein Error
ausgelöst werden sollte) im Programm aufgetreten ist: Diese Fehler sind zu schwerwiegend. Sie können den Benutzer lediglich darüber informieren, dass das Programm abstürzt, und/oder alle bekannten Informationen über den Fehler in das Programmprotokoll schreiben.
Exception
Klasse
Die Klassen Exception
und RuntimeException
sind für häufige Fehler vorgesehen, die bei der Ausführung vieler Methoden auftreten. Das Ziel jeder ausgelösten Ausnahme besteht darin, von einem Block abgefangen zu werden, der weiß, wie er richtig damit umgeht.catch
Wenn eine Methode aus irgendeinem Grund ihre Arbeit nicht abschließen kann, sollte sie die aufrufende Methode sofort benachrichtigen, indem sie eine Ausnahme des entsprechenden Typs auslöst.
Mit anderen Worten: Wenn eine Variable gleich ist null
, löst die Methode einen aus NullPointerException
. Wenn der Methode die falschen Argumente übergeben wurden, wird eine ausgelöst InvalidArgumentException
. Wenn die Methode versehentlich durch Null dividiert, wird ein Fehler ausgegeben ArithmeticException
.
RuntimeException
Klasse
RuntimeExceptions
sind eine Teilmenge von Exceptions
. Wir könnten sogar sagen, dass RuntimeException
es sich um eine vereinfachte Version gewöhnlicher Ausnahmen handelt ( Exception
) – für solche Ausnahmen gelten weniger Anforderungen und Einschränkungen
Exception
Den Unterschied zwischen und erfahren Sie RuntimeException
später.
2. Throws
: geprüfte Ausnahmen
Alle Java-Ausnahmen fallen in zwei Kategorien: aktiviert und nicht aktiviert .
Alle Ausnahmen, die das RuntimeException
oder erben, Error
gelten als ungeprüfte Ausnahmen . Alle anderen sind geprüfte Ausnahmen .
Zwanzig Jahre nach der Einführung geprüfter Ausnahmen hält fast jeder Java-Programmierer dies für einen Fehler. In gängigen modernen Frameworks sind 95 % aller Ausnahmen ungeprüft. Die C#-Sprache, die Java fast exakt kopiert hat, hat keine geprüften Ausnahmen hinzugefügt .
Was ist der Hauptunterschied zwischen aktivierten und nicht aktivierten Ausnahmen?
Für geprüfte Ausnahmen gelten zusätzliche Anforderungen . Grob gesagt sind es diese:
Anforderung 1
Wenn eine Methode eine geprüfte Ausnahme auslöst , muss sie in ihrer Signatur den Typ der Ausnahme angeben . Auf diese Weise weiß jede Methode, die sie aufruft, dass diese „bedeutungsvolle Ausnahme“ darin auftreten könnte.
Geben Sie geprüfte Ausnahmen nach den Methodenparametern nach dem throws
Schlüsselwort an (verwenden Sie das Schlüsselwort nicht throw
versehentlich). Es sieht ungefähr so aus:
type method (parameters) throws exception
Beispiel:
geprüfte Ausnahme | ungeprüfte Ausnahme |
---|---|
|
|
Im Beispiel rechts löst unser Code eine ungeprüfte Ausnahme aus – es sind keine weiteren Maßnahmen erforderlich. Im Beispiel links löst die Methode eine geprüfte Ausnahme aus, daher throws
wird das Schlüsselwort zusammen mit dem Typ der Ausnahme zur Methodensignatur hinzugefügt.
Wenn eine Methode erwartet, mehrere geprüfte Ausnahmen auszulösen , müssen alle throws
durch Kommas getrennt nach dem Schlüsselwort angegeben werden. Die Reihenfolge ist nicht wichtig. Beispiel:
public void calculate(int n) throws Exception, IOException
{
if (n == 0)
throw new Exception("n is null!");
if (n == 1)
throw new IOException("n is 1");
}
Anforderung 2
Wenn Sie eine Methode aufrufen, deren Signatur geprüfte Ausnahmen enthält, können Sie die Tatsache, dass sie diese auslöst, nicht ignorieren.
Sie müssen alle derartigen Ausnahmen entweder abfangen, indem Sie catch
für jede Ausnahme Blöcke hinzufügen, oder indem Sie sie einer throws
Klausel für Ihre Methode hinzufügen.
Es ist, als ob wir sagen würden: „ Diese Ausnahmen sind so wichtig, dass wir sie abfangen müssen.“ Und wenn wir nicht wissen, wie wir damit umgehen sollen, muss jeder, der unsere Methode aufrufen könnte, darüber informiert werden, dass solche Ausnahmen darin auftreten können.
Beispiel:
Stellen Sie sich vor, wir schreiben eine Methode, um eine von Menschen bevölkerte Welt zu schaffen. Als Argument wird die anfängliche Personenzahl übergeben. Daher müssen wir Ausnahmen hinzufügen, wenn zu wenige Personen anwesend sind.
Die Erde erschaffen | Notiz |
---|---|
|
Die Methode löst möglicherweise zwei geprüfte Ausnahmen aus:
|
Dieser Methodenaufruf kann auf drei Arten abgewickelt werden:
1. Fangen Sie keine Ausnahmen ein
Dies geschieht am häufigsten, wenn die Methode nicht weiß, wie sie mit der Situation richtig umgehen soll.
Code | Notiz |
---|---|
|
Die aufrufende Methode fängt die Ausnahmen nicht ab und muss andere darüber informieren: Sie fügt sie ihrer eigenen throws Klausel hinzu |
2. Fangen Sie einige Ausnahmen ab
Wir behandeln die Fehler, mit denen wir umgehen können. Aber diejenigen, die wir nicht verstehen, werfen wir der aufrufenden Methode vor. Dazu müssen wir ihren Namen zur throws-Klausel hinzufügen:
Code | Notiz |
---|---|
|
Der Aufrufer fängt nur eine geprüfte Ausnahme ab – LonelyWorldException . Die andere Ausnahme muss zu ihrer Signatur hinzugefügt werden, indem sie nach dem throws Schlüsselwort angegeben wird |
3. Fangen Sie alle Ausnahmen ab
Wenn die Methode keine Ausnahmen für die aufrufende Methode auslöst, ist die aufrufende Methode immer sicher, dass alles gut funktioniert hat. Und es wird nicht in der Lage sein, Maßnahmen zur Behebung einer Ausnahmesituation zu ergreifen.
Code | Notiz |
---|---|
|
Alle Ausnahmen werden in dieser Methode abgefangen. Der Anrufer wird sicher sein, dass alles gut gelaufen ist. |
3. Mehrere Ausnahmen abfangen
Programmierer hassen es wirklich, Code zu duplizieren. Sie haben sogar ein entsprechendes Entwicklungsprinzip entwickelt – DRY : Don't Repeat Yourself. Bei der Behandlung von Ausnahmen kommt es jedoch häufig vor, dass auf einen Block mehrere Blöcke mit demselben Code try
folgen .catch
Oder es könnten 3 catch
Blöcke mit demselben Code und weitere 2 catch
Blöcke mit einem anderen identischen Code vorhanden sein. Dies ist eine Standardsituation, wenn Ihr Projekt verantwortungsvoll mit Ausnahmen umgeht.
Ab Version 7 wurde der Java-Sprache die Möglichkeit hinzugefügt, mehrere Ausnahmetypen in einem einzigen catch
Block anzugeben. Es sieht ungefähr so aus:
try
{
// Code where an exception might occur
}
catch (ExceptionType1 | ExceptionType2 | ExceptionType3 name)
{
// Exception handling code
}
Sie können so viele Blöcke haben, catch
wie Sie möchten. Ein einzelner Block kann jedoch catch
keine Ausnahmen angeben, die sich gegenseitig erben. Mit anderen Worten, Sie können kein Catch ( Exception
| RuntimeException
e) schreiben, da die RuntimeException
Klasse erbt Exception
.