it-swarm.com.de

Wurffähig fangen und spezifische Ausnahmen behandeln

Ok, ich weiß, dass das Fangen von Wurfmöglichkeiten keine gute Idee ist:

    try {
         // Some code
    } catch(Throwable e) { // Not cool!
        // handle the exception
    }

Aber vor kurzem las ich einen Code mit offener Quelle durch und sah diesen (zumindest für mich) interessanten Code:

    try {
        // Some Code
    } catch (Throwable ex){
        response = handleException(ex, resource);
    }

    private handleException(Throwable t, String resource) {
        if (t instanceof SQLEXception) {
               // Some code
        } else if (t instanceof IllegalArgumentException) {
               //some code
        } //so on and so forth
    }

Das scheint nicht so schlimm zu sein? Was ist daran falsch?

22
rhel.user

Es gibt verschiedene Gründe, warum Sie ein Throwable nicht fangen sollten. Zuallererst ist, dass ThrowableErrors enthält - und normalerweise kann eine Anwendung nicht viel tun, wenn eine davon erscheint. Auch Throwable reduziert Ihre Chancen herauszufinden, WAS passiert ist. Sie bekommen nur "etwas Schlimmes ist passiert" - was eine Katastrophe oder nur ein Ärgernis sein kann. 

Der andere Ansatz ist besser, aber ich würde Throwable natürlich nicht fangen, aber versuche, spezifischere Ausnahmen zu fangen, wenn überhaupt. Ansonsten fangen Sie alles und versuchen herauszufinden, was für ein schlimmes Ding passiert ist. Ihr Beispiel könnte geschrieben werden als ...

try {
    ...
} catch (SQLEXception ex){
    response = ... ;
} catch (IllegalArgumentException ex){
    response = ...;
}

... was die Anzahl an if ( ... instanceof ... )-Blöcken reduzieren würde (die nur benötigt werden, weil der Autor sich entschieden hat, alles in einem großen Eimer zu fangen). Ist es tatsächlich ein throws Throwable, dann haben Sie natürlich keine große Auswahl. 

19
Florian Schaetz

Sie haben recht, wenn Sie sagen, dass Throwable nicht abgefangen werden kann. Der Code, den Sie in Ihrer Frage präsentieren, fängt Throwable jedoch nicht auf böse Weise ab, aber lassen Sie uns später darüber sprechen. Für den Moment hat der Code, den Sie in Ihrer Frage angeben, mehrere Vorteile:

1. Lesbarkeit

Wenn Sie sich den Code genau ansehen, werden Sie feststellen, dass, obwohl der catch-Block eine Throwable abfängt, die handleException-Methode den Typ der ausgelösten Ausnahme überprüft und möglicherweise verschiedene Aktionen ausführt, die auf dem Ausnahmetyp basieren.

Der in Ihrer Frage dargestellte Code bedeutet:

try {
    doSomething();
} catch (SQLEXception ex){
    response = handleException(resource);
} catch(IllegalArgumentException ex) {
    response = handleException(resource);
} catch(Throwable ex) {
    response = handleException(resource);
}

Selbst wenn Sie nur über 10 Ausnahmen fangen müssen, kann dieser Code leicht viele Codezeilen beanspruchen, und das Multi-Catch-Konstrukt macht den Code nicht sauberer. Der Code, den Sie in Ihrer Frage enthalten, besteht einfach darin, die Variable catch an eine andere Methode zu delegieren, um die eigentliche Methode, die die Arbeit erleichtert, lesbarer zu machen. 

2. Wiederverwendbarkeit

Der Code für die Methode " handleRequest " kann leicht geändert und in eine Dienstprogrammklasse eingefügt und in der gesamten Anwendung aufgerufen werden, um sowohl Exceptions als auch Errors zu verarbeiten. Sie können die Methode sogar in zwei private-Methoden extrahieren. Einer, der mit Exception arbeitet, und einer, der mit Error arbeitet und über die handleException-Methode verfügt, die dazu führt, dass eine Throwable die Aufrufe an diese Methoden weiter delegiert. 

3. Wartbarkeit

Wenn Sie sich entscheiden, die Art und Weise zu ändern, in der Sie eine SQLExceptions in Ihrer Anwendung protokollieren, müssen Sie diese Änderung an einem einzigen Ort vornehmen, anstatt jede Methode in jeder Klasse aufzurufen, die eine SQLException auslöst.

Ist es also eine schlechte Idee, Throwable zu fangen? 

Der Code, den Sie in Ihrer Frage angeben, ist nicht wirklich gleichbedeutend mit dem Einfangen von Throwable. Der folgende Code ist ein großes Nein: 

try {
   doSomething();
} catch(Throwable e) {
    //log, rethrow or take some action
}

Sie sollten Throwable oder Exception so weit wie möglich in der catch-Kette einfangen.

Denken Sie daran, dass es sich bei dem in Ihrer Frage enthaltenen Code um den Code des Frameworks handelt und dass es bestimmte Fehler gibt, die das Framework noch beheben kann. Siehe Wenn Sie Java.lang.Error fangen, um eine bessere Erklärung zu erhalten.

18
CKing

Faulenzen von Throwables ist eine schlechte Idee.

Dies war vor der Einführung von try-multi-catch besonders verlockend.

try {
   ...
} catch (SomeException e) {
   //do something
} catch (OtherException e) {
   //do the same thing
} ...

Das Wiederholen von catch-Blöcken ist langweilig und wortreich, weshalb sich einige Leute entschieden haben, Exception oder Throwable zu fangen und damit fertig zu werden. Dies sollte vermieden werden, weil:

  1. Es ist schwierig, dem zu folgen, was Sie versuchen.
  2. Sie könnten am Ende eine Menge Dinge fangen, mit denen Sie nicht fertig werden können. 
  3. Sie verdienen eine Bonusstrafe, wenn Sie die Throwable im Fangblock vollständig verschlucken. (Und wir haben alle Code gesehen, der das tut ... :))

Aber Throwables zu fangen, wenn es absolut notwendig ist, ist in Ordnung.

Wann ist es notwendig Sehr selten. Im Code im Framework-Stil gibt es verschiedene Szenarien (das dynamische Laden einer externen Klasse ist das offensichtlichste). In einer eigenständigen Anwendung ist es ein typisches Beispiel, eine Fehlermeldung vor dem Beenden anzuzeigen/zu protokollieren. (Bedenken Sie, dass der Versuch möglicherweise fehlschlägt, so dass Sie keine kritischen Elemente dort ablegen möchten.)

Als Faustregel gilt: Wenn es nichts gibt, was Sie bezüglich einer Ausnahme/eines Fehlers tun können, sollten Sie es überhaupt nicht fangen.

9
biziclop

Es gibt genau zwei gültige Verwendungsmöglichkeiten für die Verwendung eines großen Netzes:

  • Wenn Sie alles einheitlich behandeln, z. B. einen Top-Catch für Protokollierung/Berichterstellung, möglicherweise gefolgt von einem sofortigen Beenden.

  • Um die Duplizierung zu reduzieren, exportieren Sie das gesamte Handling in eine eigene Methode.
    Fangen Sie den am meisten abgeleiteten gemeinsamen Vorfahren ab, um zusätzliche Arbeit zu vermeiden und die Klarheit zu erhöhen.
    TROCKEN ist ein wichtiges Konstruktionsprinzip.

Wenn Sie diese Ausnahme nicht erwartet und vollständig behandelt haben, führen Sie in beiden Fällen erneut aus.

3
Deduplicator

Sie haben einen Link zu Jongo gepostet, der eine mögliche Verwendung dieser Technik demonstriert: Wiederverwendung von Fehlerbehandlungscode.

Nehmen wir an, Sie haben einen großen Block mit Fehlerbehandlungscode, der sich natürlich an verschiedenen Stellen in Ihrem Code wiederholt. Beispielsweise erzeugt Jongo Standardantworten für einige Standardklassen von Fehlern. Es kann eine gute Idee sein, diesen Fehlerbehandlungscode in eine Methode zu extrahieren, damit Sie ihn an allen Stellen wieder verwenden können, die er benötigt.

Dies bedeutet jedoch nicht, dass mit dem Code von Jongo nichts falsch ist.

Throwable (anstelle von Multicatch) zu fangen, ist immer noch verdächtig, da Sie Errors wahrscheinlich fangen, für die Sie nicht wirklich in der Lage sind, damit umzugehen (sind Sie sicher Sie wollten ThreadDeath?). Wenn Sie unbedingt Throwable fangen müssen, ist es in dieser Situation besser, "zu fangen und loszulassen" (d. H. Alles zurückzudrehen, was Sie nicht fangen wollten). Jongo macht das nicht.

3
James_pic

Nur um das Gleichgewicht zu schaffen - es gibt einen Ort, an dem ich immer catch (Throwable):

public static void main(String args[]) {
    try {
        new Test().test();
    } catch (Throwable t) {
        t.printStackTrace(System.err);
    }
}

Zumindest zeigt irgendwo etwas, dass etwas schief gelaufen ist.

2
OldCurmudgeon

Der Throwable-Effekt macht Ihre Anwendung vor allem intransparent. Sie sollten so genau wie möglich beim Erkennen von Ausnahmen sein, um in Ausnahmefällen eine gute Rückverfolgbarkeit zu ermöglichen.

Betrachten wir die Methode handleException (...) und sehen Sie einige Probleme, die bei diesem Ansatz auftreten:

  • sie fangen Throwable, behandeln aber nur Ausnahmen, was passiert, wenn ein z. OutOfMemoryError vom Typ Fehler wird ausgelöst? - Ich sehe schlechte Dinge zu passieren ...
  • Im Hinblick auf eine gute objektorientierte Programmierung unter Verwendung von instanceof wird das Open-Closed-Prinzip gebrochen und Codeänderungen (z. B. das Hinzufügen neuer Ausnahmen) werden wirklich chaotisch.

Aus meiner Sicht sind catch-Blöcke genau auf die Funktionalität zugeschnitten, die in handleExceptions (...) behandelt werden soll. Verwenden Sie sie also.

2
crazzle

Java 7 löst ein wenig von der Langeweile, die ähnliche Ausnahmen mit ähnlicher Handhabung abfängt. Sie sollten definitiv nicht das tun, was die Person hier getan hat. Fangen Sie einfach die entsprechenden Ausnahmen nach Bedarf ab, es kann hässlich aussehen, aber dafür ist throws gedacht, übergeben Sie es an die Methode, die es abfangen soll, und Sie sollten nicht zu viel Code-Speicherplatz verschwenden.

Überprüfen Sie diesen Link für weitere Informationen.

2
insidesin

Sie können immer verschiedene Ausnahmen abfangen und einige Vorgänge basierend auf dem Typ der erhaltenen Ausnahme ausführen.

Hier ist ein Beispiel

          try{

              //do something that could throw an exception

             }catch (ConnectException e) {
                //do something related to connection


            } catch (InvalidAttributeValueException e) {
                // do anything related to invalid attribute exception

            } catch (NullPointerException e) {

                // do something if a null if obtained
            }

            catch (Exception e) {
            // any other exception that is not handled can be catch here, handle it here

            }
            finally{
          //perform the final operatin like closing the connections etc.
             }
0