Восстановление исключений в Java без потери трассировки стека

417

В C # я могу использовать throw;инструкцию, чтобы перебросить исключение при сохранении трассировки стека:

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

Есть ли что-то подобное в Java ( что не теряет оригинальную трассировку стека )?

ripper234
источник
4
Как вы думаете, почему он теряет оригинальную трассировку стека? Единственный способ потерять его, когда вы генерируете новое SomeOtherException и забываете указать основную причину в конструкторе или в initCause ().
akarnokd
4
Я верю, что так ведет себя код в .Net, но я больше не уверен. Возможно, стоит поискать его где-нибудь или провести небольшой тест.
ripper234
11
Throwables не изменяются, бросая их. Чтобы обновить трассировку стека, вам нужно позвонить fillInStackTrace(). Удобно, чтобы этот метод вызывался в конструкторе a Throwable.
Роберт
51
В C # да throw e;потеряет трассировку стека. Но не на Яве.
Тим Гудман
Некоторые документы Oracle об исключениях с помощью Java 7: перехват нескольких типов исключений и повторное создание исключений с улучшенной проверкой типов
Гийом Хуста,

Ответы:

562
catch (WhateverException e) {
    throw e;
}

просто отбросит исключение, которое вы поймали (очевидно, окружающий метод должен разрешить это через свою подпись и т. д.). Исключение сохранит исходную трассировку стека.

Брайан Агнью
источник
4
Привет, InterruptedException e выдает необработанное сообщение об исключении, когда я добавляю строку выброса e. Не так, если я заменю его более широким исключением e. Как это должно быть сделано правильно?
Джеймс П.
1
@James, я только что заметил, что сообщение пропадает, если в объявлении функции добавляется «throws XxxException».
Shiouming
2
В Java 7 компилятор для такого перевоспитания более сообразителен. Теперь он отлично работает с конкретными исключениями типа «throws» в содержащем методе.
Вальдемар Восински
193
@ Джеймс, если вы с catch(Exception e) { throw e; }этим не справитесь. Если вам catch(InterruptedException ie) { throw ie; }это будет обработано. Как правило, не надо catch(Exception e)- это не покемон, и мы не хотим их всех ловить!
CorsiKa
3
@corsiKa Это не обязательно правда, что вы не хотите «поймать их всех», это просто другой вариант использования. Если у вас есть цикл верхнего уровня или обработчик событий (например, внутри прогона потока), если вы не перехватите хотя бы RuntimeException и не зарегистрируете его, вы часто пропустите это исключение И молча выйдете из важного цикла, для чего часто бывает разовым провалом. Это также очень хорошо для функциональности плагинов, когда вы не знаете, что может делать или выбрасывать дополнительный код ... Для нисходящих операций, подобных этим, исключение часто является не только хорошей идеей, но и лучшей практикой.
Билл К
82

Я бы предпочел:

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
Определенно уместно в Java для отлова определенных исключений, кроме generic, и проверки на наличие экземпляров. +1
amischiefr
8
-1 потому что вы никогда не должны ловить простое «исключение», если не знаете, что делаете.
Стробоскоп
19
@Stroboskop: правда, но для ответа лучше использовать тот же (похожий) код, что и в вопросе!
user85421
14
Иногда ловить все исключения в порядке. Например, когда вы пишете контрольный пример. Или для целей регистрации. Или в основном, где не ловить означает сбой.
Джон Хенкель
1
@JohnHenckel и другие: действительные точки вписаны. Я обновил вопрос, чтобы прояснить, что Exceptionв большинстве (но не во всех) случаях отлов обычно не является правильным решением .
Пер Лундберг
74

Вы также можете заключить исключение в другое И сохранить исходную трассировку стека, передав исключение как Throwable в качестве параметра причины:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}
Olvagor
источник
8
Я также посоветовал бы добавить сообщение вместе, используяthrow new YourOwnException("Error while trying to ....", e);
Julien
это то, что я искал, особенно версия из первого комментария, где вы можете передать свое собственное сообщение
Csaba
Это показывает сообщение об ошибке правильно, но трассировка стека показывает строку ошибки как строку с «throw new ....... (e)», а не исходную строку, вызвавшую исключение.
Ашберн РК
22

В Java это почти то же самое:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}
Алвес
источник
5
Нет, до тех пор, пока вы не создадите новый объект-исключение, трассировка стека останется прежней.
Mnementh
28
Я хотел бы добавить определенный улов для FooException
DFA
3
В этом конкретном случае я согласен, но добавление определенного улова может быть неправильным выбором - представьте, что у вас есть какой-то общий код для всех исключений, а после, для конкретного исключения, сбросьте его.
Алвес
1
@MarkusLausberg Но, наконец, не ловит исключения.
Роберт
Да, но это был не вопрос.
Маркус Лозберг
14

В Java вы просто генерируете исключение, которое вы поймали, throw eа не просто throw. Java поддерживает трассировку стека.

Дэвид М
источник
6

что-то вроде этого

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
cdeszaq
источник
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;
    }
}

Это конкретный пример, где метод выдает IOException. В finalсредстве tможет содержать только исключение брошенного из блока Try. Дополнительные материалы для чтения можно найти здесь и здесь .

Даниил
источник
1
Это не должно быть окончательным. См. Docs.oracle.com/javase/7/docs/technotes/guides/language/… и stackoverflow.com/a/6889301/131160
jcsahnwaldt говорит, что GoFundMonica
3

Трассировка стека сохраняется, если вы переворачиваете пойманное исключение в другое исключение (для получения дополнительной информации) или просто перебрасываете пойманное исключение.

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

Sindre
источник
2

У меня просто была похожая ситуация, в которой мой код потенциально генерировал множество различных исключений, которые я просто хотел перебросить. Решение, описанное выше, не работает для меня, потому что Eclipse сказал мне, что throw e;приводит к необработанному исключению, поэтому я просто сделал это:

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

Работал на меня .... :)

Матиас
источник