Ponowne przeglądanie wyjątków w Javie bez utraty śladu stosu


417

W języku C # mogę użyć throw;instrukcji, aby ponownie wygenerować wyjątek, zachowując ślad stosu:

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

Czy jest coś takiego w Javie ( która nie traci pierwotnego śladu stosu )?


4
Jak myślisz, dlaczego traci pierwotny ślad stosu? Jedyny sposób, aby go zgubić, gdy rzucisz nowy SomeOtherException i zapomnisz przypisać główną przyczynę w konstruktorze lub w initCause ().
akarnokd

4
Wierzę, że tak zachowuje się kod w .Net, ale nie jestem już pozytywny. Warto gdzieś to sprawdzić lub przeprowadzić mały test.
ripper234

11
Throwablenie są modyfikowane przez ich rzucanie. Aby zaktualizować ślad stosu, musisz wywołać fillInStackTrace(). Dogodnie ta metoda jest wywoływana w konstruktorze Throwable.
Robert

50
Tak, w C # throw e;utraci ślad stosu. Ale nie w Javie.
Tim Goodman

Odpowiedzi:


560
catch (WhateverException e) {
    throw e;
}

po prostu zwróci wyjątek, który złapałeś (oczywiście otaczająca metoda musi na to pozwolić poprzez swój podpis itp.). Wyjątek zachowa oryginalny ślad stosu.


4
Cześć, InterruptedException e daje nieobsługiwany komunikat wyjątku, gdy dodam linię „throw e”. Nie tak, jeśli zastąpię go szerszym wyjątkiem e. Jak należy to zrobić poprawnie?
James P.

1
@James, właśnie zauważyłem, że komunikat znika, jeśli dodanie „zgłasza wyjątek XxxExx” w deklaracji funkcji.
shiouming

2
W Javie 7 kompilator do takiego powrotu jest bardziej inteligentny. Teraz działa dobrze z określonymi wyjątkami „rzuca” w metodzie zawierającej.
Waldemar Wosiński

193
@James Jeśli to nie catch(Exception e) { throw e; }będzie możliwe. Jeśli catch(InterruptedException ie) { throw ie; }to zostanie załatwione. Zasadniczo, nie rób catch(Exception e)- to nie jest pokemon i nie chcemy ich wszystkich złapać!
corsiKa

3
@corsiKa To niekoniecznie prawda, że ​​nie chcesz „złapać ich wszystkich”, to po prostu inny przypadek użycia. Jeśli masz pętlę najwyższego poziomu lub moduł obsługi zdarzeń (na przykład wewnątrz przebiegu wątku), jeśli nie złapiesz przynajmniej wyjątku RuntimeException i nie zarejestrujesz go, często często całkowicie pomijasz wyjątek ORAZ po cichu wyłamujesz się z ważnej pętli jest często jednorazową porażką. Jest również bardzo dobry dla funkcji wtyczek, w których nie wiesz, co dodatkowy kod może zrobić lub rzucić ... Do zastosowań odgórnych, takich jak wyłapywanie wyjątków Często wyjątek jest nie tylko dobrym pomysłem, ale najlepszą praktyką.
Bill K

82

Wolałbym:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}

6
Zdecydowanie właściwe w Javie do wychwytywania określonych wyjątków niż ogólne i sprawdzanie na przykład. +1
amischiefr

8
-1, ponieważ nigdy nie powinieneś wychwytywać „wyjątku”, chyba że wiesz, co robisz.
Stroboskop

19
@Stroboskop: prawda, ale aby odpowiedzieć, najlepiej użyć tego samego (podobnego) kodu jak w pytaniu!
user85421,

14
Czasami łapanie wszystkich wyjątków jest w porządku. Na przykład, gdy piszesz przypadek testowy. Lub do celów logowania. Lub w zasadzie tam, gdzie nie złapanie oznacza rozbicie.
John Henckel,

1
@JohnHenckel i inni: Prawidłowe punkty inded. Zaktualizowałem pytanie, aby wyjaśnić, że łapanie Exceptionzwykle nie jest właściwym rozwiązaniem w większości (ale nie wszystkich) przypadkach.
Per Lundberg,

74

Możesz także owinąć wyjątek w inny ORAZ zachować ślad oryginalnego stosu, przekazując wyjątek jako Throwable jako parametr przyczyny:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}

8
Radziłbym również dodać wiadomość obok, używającthrow new YourOwnException("Error while trying to ....", e);
Julien

tego właśnie szukałem, zwłaszcza wersja z pierwszego komentarza, w której możesz przekazać własną wiadomość
Csaba

To pokazuje komunikat o błędzie poprawnie, ale ślad stosu pokazuje linię błędu jako linię z „wyrzuć nowy ....... (e)”, a nie oryginalną linię, która spowodowała wyjątek.
Ashburn RK

22

W Javie jest prawie tak samo:

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

5
Nie, dopóki nie utworzysz nowego obiektu wyjątku, stacktrace pozostaje taki sam.
Mnementh

28
Dodam zaczep specyficzny dla FooException
dfa

3
W tym konkretnym przypadku zgadzam się, ale dodanie konkretnego haczyka może nie być właściwym wyborem - wyobraź sobie, że masz jakiś wspólny kod dla wszystkich wyjątków, a po, dla konkretnego wyjątku, ponownie go zwróć.
alves

1
@MarkusLausberg Ale w końcu nie łapie wyjątków.
Robert

Tak, ale to nie było pytanie.
Markus Lausberg

14

W Javie po prostu rzucasz wyjątek, który złapałeś, throw ea nie tylko throw. Java utrzymuje śledzenie stosu.


6

coś takiego

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

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;
    }
}

Jest to konkretny przykład, w którym metoda rzuca an IOException. Te finalśrodki tmogą posiadać tylko wyjątek wyrzucony z bloku try. Dodatkowe materiały do ​​czytania można znaleźć tutaj i tutaj .



3

Śledzenie stosu jest zachowywane, jeśli złapiesz wychwycony ekscytację w inny wyjątek (aby uzyskać więcej informacji) lub jeśli po prostu ponownie rzucisz złapany wykop.

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


2

Właśnie miałem podobną sytuację, w której mój kod potencjalnie generuje wiele różnych wyjątków, które chciałem po prostu ponownie wprowadzić. Rozwiązanie opisane powyżej nie działało dla mnie, ponieważ Eclipse powiedział mi, że throw e;prowadzi to do niewymienionego wyjątku, więc właśnie to zrobiłem:

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

Pracował dla mnie .... :)

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.