Wann fängt man java.lang.Error?


Antworten:


101

Im Allgemeinen niemals.

Manchmal müssen Sie jedoch bestimmte Fehler abfangen.

Wenn Sie Framework-Code schreiben (Laden von Klassen von Drittanbietern), ist es möglicherweise ratsam, ihn abzufangen LinkageError(keine Klassendefinition gefunden, unbefriedigter Link, inkompatibler Klassenwechsel).

Ich habe auch einige dumme Codes von Drittanbietern gesehen, die Unterklassen von werfen Error, also müssen Sie auch damit umgehen.

Ich bin mir übrigens nicht sicher, ob es nicht möglich ist, sich davon zu erholen OutOfMemoryError.


3
Dass ich genau tun musste, um DLLs zu laden, würde fehlschlagen, wenn sie nicht richtig konfiguriert wären. Kein schwerwiegender Fehler bei dieser Anwendung.
Mario Ortegón

7
Manchmal ist es sinnvoll, OutOfMemoryError abzufangen - beispielsweise beim Erstellen großer Array-Listen.
SpaceTrucker

3
@SpaceTrucker: Funktioniert dieser Ansatz in Multithread-Anwendungen gut oder besteht ein erhebliches Risiko, dass kleinere Zuordnungen in anderen Threads dadurch fehlschlagen? … Vermutlich nur, wenn Ihre Arrays gerade klein genug waren, um zugewiesen zu werden, aber nichts für andere übrig ließen.
PJTraill

@PJTraill Da bin ich mir nicht sicher. Dies würde einige statistische Stichproben der realen Welt erfordern. Ich dachte, ich hätte einen solchen Code gesehen, kann mich aber nicht erinnern, wo er war.
SpaceTrucker

51

Noch nie. Sie können nie sicher sein, dass die Anwendung die nächste Codezeile ausführen kann. Wenn Sie eine erhalten OutOfMemoryError, haben Sie keine Garantie dafür, dass Sie in der Lage sind, alles zuverlässig zu tun . Catch RuntimeException und aktivierte Ausnahmen, aber niemals Fehler.

http://pmd.sourceforge.net/rules/strictexception.html


27
Sag niemals nie. Wir haben Testcode, der ein "Assert False" ausführt. fängt dann den AssertionError ab, um sicherzustellen, dass das Flag -ea gesetzt ist. Davon abgesehen ... ja, wahrscheinlich nie ;-)
Outlaw Programmer

3
Wie wäre es mit einer Serveranwendung, die Anforderungen an Arbeitsthreads weiterleitet? Könnte es nicht sinnvoll sein, Throwable im Worker-Thread zu fangen, um Fehler abzufangen, und zumindest zu versuchen, zu protokollieren, was schief gelaufen ist?
Leigh

11
Niemals ... außer wenn es unbedingt nötig ist. Niemals ist ein starkes Wort und es gibt immer Ausnahmen von den Regeln. Wenn Sie ein Framework erstellen, ist es nicht unwahrscheinlich, dass Sie bestimmte Fehler abfangen und behandeln müssen, selbst wenn es sich nur um eine Protokollierung handelt.
Robin

Wie wäre es mit Fehlern, z. B. NoSuchMethodError, die von Bibliotheksmethoden von Drittanbietern stammen?
ha9u63ar

@OutlawProgrammer Nur zur Veranschaulichung, es gibt andere Möglichkeiten, den gleichen Test durchzuführen:boolean assertionsEnabled = false; assert assertionsEnabled = true;
Shmosel

16

Im Allgemeinen sollten Sie es immer abfangen java.lang.Errorund in ein Protokoll schreiben oder dem Benutzer anzeigen. Ich arbeite im Support und sehe täglich, dass Programmierer nicht sagen können, was in einem Programm passiert ist.

Wenn Sie einen Daemon-Thread haben, müssen Sie verhindern, dass dieser beendet wird. In anderen Fällen funktioniert Ihre Anwendung ordnungsgemäß.

Sie sollten nur java.lang.Errorauf höchstem Niveau fangen .

Wenn Sie sich die Liste der Fehler ansehen, werden Sie feststellen, dass die meisten Fehler behoben werden können. Beispielsweise ZipErrortritt beim Lesen beschädigter Zip-Dateien ein Fehler auf.

Die häufigsten Fehler sind OutOfMemoryErrorund NoClassDefFoundError, die in den meisten Fällen Laufzeitprobleme sind.

Beispielsweise:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

kann ein produzieren, OutOfMemoryErroraber es ist ein Laufzeitproblem und kein Grund, Ihr Programm zu beenden.

NoClassDefFoundErrortreten meistens auf, wenn eine Bibliothek nicht vorhanden ist oder wenn Sie mit einer anderen Java-Version arbeiten. Wenn es ein optionaler Teil Ihres Programms ist, sollten Sie Ihr Programm nicht beenden.

Ich kann noch viele weitere Beispiele dafür nennen, warum es eine gute Idee ist, Throwableauf höchster Ebene zu fangen und eine hilfreiche Fehlermeldung zu erstellen.


Ich würde vermuten, dass es in diesen Fällen besser ist, den Dämon mit den richtigen Warnungen zu versagen, als die Möglichkeit zu haben, dass er als ätherischer Geist auf einem fehlgeschlagenen JVM am Leben bleibt, wo er den falschen Vorwand gibt, dass er wirklich lebt und etwas tut
Andrew Norman

OutOfMemoryErrorist kein Laufzeitfehler. Es gibt keine Garantie dafür, dass die Anwendung ihn wiederherstellen kann. Wenn Sie Glück haben, erhalten Sie möglicherweise OOM, new byte[largeNumber]aber wenn diese Zuordnung nicht ausreicht, um OOM zu verursachen, kann sie in der nächsten Zeile oder im nächsten Thread ausgelöst werden. Dies ist ein Laufzeitproblem, da lengthnicht vertrauenswürdige Eingaben vor dem Aufruf überprüft werden sollten new byte[].
Jeeyoung Kim

NoClassDefFoundErrorkann überall auftreten , da es aufgerufen wird, wenn kompilierter Java-Code keine Klasse finden kann. Wenn Ihr JDK falsch konfiguriert ist, kann dies durch den Versuch ausgelöst werden, eine java.util.*Klasse zu verwenden , und es ist praktisch unmöglich, dagegen zu programmieren. Wenn Sie optional eine Abhängigkeit einschließen, sollten Sie verwenden, um ClassLoaderzu überprüfen, ob sie existiert und welche ausgelöst wird ClassNotFoundException.
Jeeyoung Kim

1
ZipErrorGibt an, dass die JAR-Datei mit Klassen eine beschädigte Zip-Datei ist. Dies ist ein ziemlich ernstes Problem, und zu diesem Zeitpunkt können Sie keinem Code vertrauen, der ausgeführt wird, und es wäre unverantwortlich, wenn Sie versuchen würden, ihn "wiederherzustellen".
Jeeyoung Kim

2
Im Allgemeinen kann es hilfreich sein, etwas zu fangen java.lang.Erroroder java.lang.Throwableauf höchster Ebene zu versuchen, etwas damit zu tun - beispielsweise eine Fehlermeldung zu protokollieren. Zu diesem Zeitpunkt gibt es jedoch keine Garantie dafür, dass dies ausgeführt wird. Wenn Ihre JVM OOM-fähig ist, kann der Versuch, sich zu protokollieren, mehr Strings zuweisen, wodurch ein anderes OOM ausgelöst wird.
Jeeyoung Kim

15

In einer Multithread-Umgebung möchten Sie es am häufigsten fangen! Wenn Sie es fangen, protokollieren Sie es und beenden Sie die gesamte Anwendung! Wenn Sie das nicht tun, ist ein Thread, der möglicherweise einen entscheidenden Teil leistet, tot, und der Rest der Anwendung wird denken, dass alles normal ist. Daraus können viele unerwünschte Situationen entstehen. Ein kleinstes Problem ist, dass Sie die Ursache des Problems nicht leicht finden können, wenn andere Threads einige Ausnahmen auslösen, weil ein Thread nicht funktioniert.

Zum Beispiel sollte eine Schleife normalerweise sein:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

Selbst in einigen Fällen möchten Sie verschiedene Fehler unterschiedlich behandeln. In OutOfMemoryError können Sie beispielsweise die Anwendung regelmäßig schließen (möglicherweise sogar Speicher freigeben und fortfahren). In anderen Fällen können Sie nicht viel tun.


1
Es ist unklug, zu fangen OutOfMemoryError und fortzufahren, anstatt sofort zu existieren, da sich Ihr Programm dann in einem undefinierten Zustand befindet .
Raedwald

1
Das Aufrufen des Systems beim Beenden eines Wurfobjekts hat die unbeabsichtigte Folge, dass alles, was auf der JVM ausgeführt wird, und nicht nur die betreffende Anwendung beendet wird. Normalerweise keine gute Vorgehensweise für Webanwendungen, die möglicherweise auf einem App-Server mit anderen Webanwendungen gehostet werden (ganz zu schweigen davon, dass dies Auswirkungen auf den App-Server selbst hat).
Andrew Norman

9

Sehr selten.

Ich würde nur auf der obersten Ebene eines Threads sagen, dass ATTEMPT eine Nachricht mit dem Grund für das Absterben eines Threads ausgeben soll.

Wenn Sie sich in einem Framework befinden, das so etwas für Sie erledigt, überlassen Sie es dem Framework.


6

Fast nie. Fehler sind Probleme, gegen die Anwendungen im Allgemeinen nichts unternehmen können. Die einzige Ausnahme könnte darin bestehen, die Darstellung des Fehlers zu behandeln, aber selbst das läuft je nach Fehler möglicherweise nicht wie geplant.


6

Ein Errorsollte normalerweise nicht gefangen werden , da dies auf einen abnormalen Zustand hinweist, der niemals auftreten sollte .

Aus der Java-API-Spezifikation für die ErrorKlasse:

Eine ErrorUnterklasse Throwable davon weist auf schwerwiegende Probleme hin, die eine vernünftige Anwendung nicht abfangen sollte. Die meisten dieser Fehler sind abnormale Zustände. [...]

Eine Methode muss in ihrer Throws-Klausel keine Fehlerklassen deklarieren, die möglicherweise während der Ausführung der Methode ausgelöst, aber nicht abgefangen werden, da diese Fehler abnormale Bedingungen sind, die niemals auftreten sollten.

Wie in der Spezifikation erwähnt, wird ein Errornur unter Umständen ausgelöst, bei denen Errordie Anwendung möglicherweise nur sehr wenig tun kann, und unter bestimmten Umständen befindet sich die Java Virtual Machine selbst möglicherweise in einem instabilen Zustand (zVirtualMachineError )

Obwohl an Erroreine Unterklasse ist Throwable, bedeutet dies, dass es von a gefangen werden kanntry-catch Klausel , aber es wird wahrscheinlich nicht wirklich benötigt, da sich die Anwendung in einem abnormalen Zustand befindet, wenn einError von der JVM ausgelöst wird.

Es gibt auch einen kurzen Abschnitt zu diesem Thema in Abschnitt 11.5 Die Ausnahmehierarchie der Java-Sprachspezifikation, 2. Ausgabe .


6

Wenn Sie verrückt genug sind, um ein neues Unit-Test-Framework zu erstellen, muss Ihr Testläufer wahrscheinlich java.lang.AssertionError abfangen, das von Testfällen ausgelöst wird.

Andernfalls sehen Sie andere Antworten.


5

Und es gibt noch einige andere Fälle, in denen Sie einen Fehler erneut auslösen müssen, wenn Sie ihn feststellen . Zum Beispiel sollte ThreadDeath niemals abgefangen werden, es kann ein großes Problem verursachen, wenn Sie es in einer geschlossenen Umgebung (z. B. einem Anwendungsserver) abfangen:

Eine Anwendung sollte Instanzen dieser Klasse nur abfangen, wenn sie nach dem asynchronen Beenden bereinigt werden muss. Wenn ThreadDeath von einer Methode abgefangen wird, ist es wichtig, dass es erneut geworfen wird, damit der Thread tatsächlich stirbt.


2
Welches ist eigentlich kein Problem, weil Sie einfach nichtError s fangen .
Bombe

4

Sehr, sehr selten.

Ich habe es nur für einen sehr sehr spezifischen bekannten Fall getan. Beispielsweise könnte java.lang.UnsatisfiedLinkError ausgelöst werden, wenn zwei unabhängige ClassLoader dieselbe DLL laden. (Ich bin damit einverstanden, dass ich die JAR auf einen gemeinsam genutzten Klassenladeprogramm verschieben soll.)

Der häufigste Fall ist jedoch, dass Sie eine Protokollierung benötigen, um zu wissen, was passiert ist, wenn Benutzer sich beschweren. Sie möchten eine Nachricht oder ein Popup an den Benutzer, anstatt stillschweigend tot zu sein.

Selbst Programmierer in C / C ++ geben einen Fehler ein und sagen etwas, was die Leute nicht verstehen, bevor es beendet wird (z. B. Speicherfehler).


3

In einer Android-Anwendung fange ich einen java.lang.VerifyError ab . Eine Bibliothek, die ich verwende, funktioniert nicht auf Geräten mit einer alten Version des Betriebssystems, und der Bibliothekscode löst einen solchen Fehler aus. Ich könnte den Fehler natürlich vermeiden, indem ich zur Laufzeit die Version des Betriebssystems überprüfe, aber:

  • Das älteste unterstützte SDK kann sich in Zukunft für die jeweilige Bibliothek ändern
  • Der Try-Catch-Fehlerblock ist Teil eines größeren Fallback-Mechanismus. Einige bestimmte Geräte lösen Ausnahmen aus, obwohl sie die Bibliothek unterstützen sollen. Ich fange VerifyError und alle Ausnahmen ab, um eine Fallback-Lösung zu verwenden.

3

Es ist sehr praktisch, java.lang.AssertionError in einer Testumgebung abzufangen ...


Welchen Wert möchten Sie hinzufügen?
lpapp

Hinzufügen des Werts einer Testsuite, die nicht abgebrochen wird
Jono

2

Idealerweise sollten wir keine Fehler behandeln / abfangen. Es kann jedoch Fälle geben, in denen dies aufgrund der Anforderungen an das Framework oder die Anwendung erforderlich ist. Angenommen, ich habe einen XML-Parser-Daemon, der den DOM-Parser implementiert, der mehr Speicher benötigt. Wenn es eine Anforderung gibt, wie der Parser-Thread beim Abrufen von OutOfMemoryError nicht beendet werden sollte , sollte er stattdessen damit umgehen und eine Nachricht / E-Mail an den Administrator der Anwendung / des Frameworks senden.


1

Im Idealfall sollten wir niemals Fehler in unserer Java-Anwendung abfangen, da dies ein abnormaler Zustand ist. Die Anwendung würde sich in einem abnormalen Zustand befinden und könnte zu Carshing führen oder zu einem ernsthaft falschen Ergebnis führen.


1

Es kann angebracht sein, Fehler bei Komponententests abzufangen, die überprüfen, ob eine Aussage getroffen wurde. Wenn jemand Zusicherungen deaktiviert oder die Zusicherung auf andere Weise löscht, möchten Sie dies wissen


1

Es liegt ein Fehler vor, wenn die JVM nicht mehr wie erwartet funktioniert oder kurz davor steht. Wenn Sie einen Fehler abfangen, gibt es keine Garantie dafür, dass der catch-Block ausgeführt wird, und noch weniger, dass er bis zum Ende ausgeführt wird.

Dies hängt auch vom laufenden Computer und dem aktuellen Speicherstatus ab, sodass Sie nicht testen, versuchen und Ihr Bestes geben können. Sie werden nur ein hasardous Ergebnis haben.

Sie werden auch die Lesbarkeit Ihres Codes herabstufen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.