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


417

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

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

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


4
Как вы думаете, почему он теряет оригинальную трассировку стека? Единственный способ потерять его, когда вы генерируете новое SomeOtherException и забываете указать основную причину в конструкторе или в initCause ().
akarnokd

4
Я верю, что так ведет себя код в .Net, но я больше не уверен. Возможно, стоит поискать его где-нибудь или провести небольшой тест.
ripper234

11
Throwables не изменяются, бросая их. Чтобы обновить трассировку стека, вам нужно позвонить fillInStackTrace(). Удобно, чтобы этот метод вызывался в конструкторе a Throwable.
Роберт

51
В C # да throw e;потеряет трассировку стека. Но не на Яве.
Тим Гудман

Ответы:


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

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)
{
  ...
}

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. Дополнительные материалы для чтения можно найти здесь и здесь .



3

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

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


2

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.