Нет различий в поведении между вашими двумя примерами кода. (В частности, трассировки стека записываются при создании исключения, а не при его возникновении, поэтому повторно отправленное исключение все равно будет иметь исходную трассировку стека). Поэтому обычно люди используют более простую идиому.
Это не значит, что повторное бросание не имеет смысла. Например, если вы хотите обработать все исключения, кроме FooBarExceptions, вы можете написать:
try {
// bad code
} catch (FooBarException e) {
throw e;
} catch (Exception e) {
e.printStackTrace();
}
Или, если решение обработать исключение является более сложным, чем просто проверка его типа, вы можете просто его перехватить и перебросить, если окажется, что вы не можете его обработать:
for (int attempts = 0; attemps < 6; attempts++) {
try {
return crankyMethod();
} catch (Exception e) {
if (fatal(e)) {
throw e;
} else {
// try again
continue;
}
}
}
Стоит отметить, что когда люди говорят «бросить», некоторые имеют в виду другое исключение, как в следующем примере:
for (int i = 0; i < array.length; i++) {
try {
process(array[i]);
} catch (Exception e) {
throw new RuntimeException("Could not process element at index " + i, e);
}
}
Преимущество этого шаблона состоит в том, чтобы украсить исходное исключение дополнительной информацией, которая может иметь значение (в приведенном выше примере: какие данные не могут быть обработаны). Обратите внимание, что исходное исключение передается в конструктор нового, поэтому его трассировка стека не теряется.