Ausnahmen in Java erneut auslösen, ohne den Stack-Trace zu verlieren

417

In C # kann ich die throw;Anweisung verwenden, um eine Ausnahme erneut auszulösen, während die Stapelverfolgung beibehalten wird:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

Gibt es so etwas in Java ( das den ursprünglichen Stack-Trace nicht verliert )?

ripper234
quelle
4
Warum verliert es Ihrer Meinung nach die ursprüngliche Stapelspur? Die einzige Möglichkeit, es zu verlieren, wenn Sie eine neue SomeOtherException auslösen und vergessen, die Grundursache im Konstruktor oder in initCause () zuzuweisen.
Akarnokd
4
Ich glaube, so verhält sich der Code in .Net, aber ich bin nicht mehr positiv. Es könnte sich lohnen, entweder irgendwo nachzuschlagen oder einen kleinen Test durchzuführen.
Ripper234
11
Throwables werden nicht durch Werfen verändert. Um den Stack-Trace zu aktualisieren, müssen Sie aufrufen fillInStackTrace(). Praktischerweise wird diese Methode im Konstruktor von a aufgerufen Throwable.
Robert
50
In C # throw e;verliert ja die Stapelspur. Aber nicht in Java.
Tim Goodman
Einige Dokumente von Oracle über Ausnahmen mit Java 7: Abfangen mehrerer Ausnahmetypen und erneutes Auslösen von Ausnahmen mit verbesserter Typprüfung
Guillaume Husta

Antworten:

560
catch (WhateverException e) {
    throw e;
}

wird einfach die Ausnahme erneut auslösen, die Sie abgefangen haben (offensichtlich muss die umgebende Methode dies über ihre Signatur usw. zulassen). Die Ausnahme behält die ursprüngliche Stapelverfolgung bei.

Brian Agnew
quelle
4
Hallo, InterruptedException e gibt eine nicht behandelte Ausnahmemeldung aus, wenn ich die Zeile throw e hinzufüge. Nicht so, wenn ich es durch die breitere Ausnahme ersetze. E. Wie soll das richtig gemacht werden?
James P.
1
@James, ich habe gerade beobachtet, dass die Nachricht verschwindet, wenn in der Funktionsdeklaration "löst XxxException aus" hinzugefügt wird.
Shiouming
2
In Java 7 ist der Compiler für ein solches Umwerfen intelligenter. Jetzt funktioniert es gut mit bestimmten "Throws" -Ausnahmen in der enthaltenen Methode.
Waldemar Wosiński
192
@ James Wenn du catch(Exception e) { throw e; }das nicht behandeln wirst. Wenn Sie catch(InterruptedException ie) { throw ie; }es wird behandelt. Als Faustregel gilt catch(Exception e): Dies ist kein Pokemon, und wir wollen sie nicht alle fangen!
CorsiKa
3
@corsiKa Es ist nicht unbedingt wahr, dass Sie nicht "Catch 'em all" wollen, es ist nur ein anderer Anwendungsfall. Wenn Sie eine Schleife oder einen Ereignishandler der obersten Ebene haben (z. B. innerhalb eines Threads), wenn Sie nicht mindestens RuntimeException abfangen und protokollieren, verpassen Sie häufig die Ausnahme insgesamt UND brechen stillschweigend aus einer wichtigen Schleife aus ist oft ein einmaliger Fehler. Es ist auch sehr gut für Plugin-Funktionen geeignet, bei denen Sie nicht wissen, was zusätzlicher Code bewirken oder auslösen könnte ... Für Top-Down-Anwendungen wie diese ist eine Ausnahme oft nicht nur eine gute Idee, sondern auch eine bewährte Methode.
Bill K
82

Ich würde bevorzugen:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}
Markus Lausberg
quelle
6
In Java auf jeden Fall geeignet, um bestimmte Ausnahmen zu erfassen, die nicht generisch sind und beispielsweise überprüft werden. +1
amischiefr
8
-1, weil Sie niemals eine einfache "Ausnahme" abfangen sollten, es sei denn, Sie wissen, was Sie tun.
Stroboskop
19
@Stroboskop: stimmt, aber um zu antworten, ist es am besten, den gleichen (ähnlichen) Code wie in der Frage zu verwenden!
user85421
14
Manchmal ist es in Ordnung, alle Ausnahmen zu fangen. Zum Beispiel, wenn Sie einen Testfall schreiben. Oder zu Protokollierungszwecken. Oder in der Hauptsache, wo nicht fangen bedeutet abstürzen.
John Henckel
1
@ JohnHenckel und andere: Gültige Punkte angegeben. Ich habe die Frage aktualisiert, um zu verdeutlichen, dass das Fangen Exceptionin den meisten (aber nicht allen) Fällen normalerweise nicht das Richtige ist .
Per Lundberg
74

Sie können die Ausnahme auch in eine andere umschließen UND die ursprüngliche Stapelverfolgung beibehalten, indem Sie die Ausnahme als Throwable als Ursachenparameter übergeben:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}
Olvagor
quelle
8
Ich würde auch empfehlen, eine Nachricht nebenthrow new YourOwnException("Error while trying to ....", e);
Julien
Dies ist, wonach ich gesucht habe, insbesondere die Version aus dem ersten Kommentar, in der Sie Ihre eigene Nachricht weitergeben können
Csaba
Dies zeigt die Fehlermeldung korrekt an, aber die Stapelverfolgung zeigt die Fehlerzeile als Zeile mit 'throw new ....... (e)' und nicht als die ursprüngliche Zeile, die die Ausnahme verursacht hat.
Ashburn RK
22

In Java ist fast das gleiche:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}
alves
quelle
5
Nein, solange Sie kein neues Exception-Objekt instanziieren, bleibt die Stacktrace gleich.
Mnementh
28
Ich würde einen bestimmten Fang für FooException hinzufügen
dfa
3
In diesem speziellen Fall stimme ich zu, aber das Hinzufügen eines bestimmten Fangs ist möglicherweise nicht die richtige Wahl. Stellen Sie sich vor, Sie haben einen gemeinsamen Code für alle Ausnahmen und werfen ihn nach einer bestimmten Ausnahme erneut.
Alves
1
@ MarkusLausberg Aber endlich keine Ausnahmen.
Robert
Ja, aber das war nicht die Frage.
Markus Lausberg
14

In Java wird nur die Ausnahme ausgelöst, die Sie abgefangen haben, throw eund nicht nur throw. Java verwaltet den Stack-Trace.

David M.
quelle
6

etwas wie das

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
cdeszaq
quelle
5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

Dies ist ein konkretes Beispiel, bei dem die Methode ein löst IOException. Das finalMittel tkann nur eine Ausnahme enthalten, die vom try-Block ausgelöst wird. Zusätzliches Lesematerial finden Sie hier und hier .

Daniel
quelle
1
Es muss nicht endgültig sein. Siehe docs.oracle.com/javase/7/docs/technotes/guides/language/… und stackoverflow.com/a/6889301/131160
jcsahnwaldt sagt GoFundMonica
3

Die Stapelverfolgung wird beibehalten, wenn Sie die abgefangene Vervollständigung in eine andere Ausnahme einschließen (um weitere Informationen bereitzustellen) oder wenn Sie die abgefangene Vervollständigung nur erneut auslösen.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }

Sindre
quelle
2

Ich hatte gerade eine ähnliche Situation, in der mein Code möglicherweise eine Reihe verschiedener Ausnahmen auslöst, die ich nur neu werfen wollte. Die oben beschriebene Lösung hat bei mir nicht funktioniert, da Eclipse mir mitgeteilt hat, dass dies throw e;zu einer nicht gehandelten Ausnahme führt. Deshalb habe ich Folgendes getan:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

Arbeitete für mich .... :)

Matthias
quelle