Ответы:
Конструкции
try { ... }
catch () { ... } /* You can even omit the () here */
try { ... }
catch (Exception e) { ... }
похожи в том, что оба будут перехватывать каждое исключение, созданное внутри try
блока (и, если вы просто не используете это для регистрации исключений, следует избегать ). А теперь посмотрите на это:
try { ... }
catch ()
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw;
}
try { ... }
catch (Exception e)
{
/* ... */
throw e;
}
Первый и второй блоки try-catch - ТОЧНО одно и то же, они просто повторно генерируют текущее исключение, и это исключение сохранит свой «источник» и трассировку стека.
Третий блок try-catch отличается. Когда он генерирует исключение, он изменяет источник и трассировку стека, так что будет казаться, что исключение было выброшено из этого метода, из той самой строки throw e
в методе, содержащей этот блок try-catch.
Какой из них использовать? Это действительно зависит от каждого случая.
Допустим, у вас есть Person
класс с .Save()
методом, который сохранит его в базе данных. Допустим, ваше приложение Person.Save()
где-то выполняет метод. Если ваша БД отказывается сохранять человека, то .Save()
выдает исключение. Следует ли использовать throw
или throw e
в этом случае? Смотря как.
Я предпочитаю делать:
try {
/* ... */
person.Save();
}
catch(DBException e) {
throw new InvalidPersonException(
"The person has an invalid state and could not be saved!",
e);
}
Это должно поместить DBException как «внутреннее исключение» нового создаваемого исключения. Поэтому, когда вы проверяете это InvalidPersonException, трассировка стека будет содержать информацию, возвращаемую к методу Save (этого может быть достаточно для решения проблемы), но у вас все еще есть доступ к исходному исключению, если оно вам нужно.
В качестве заключительного замечания, когда вы ожидаете исключения, вы должны действительно поймать это конкретное исключение, а не общее Exception
, т.е. если вы ожидаете InvalidPersonException, вам следует предпочесть:
try { ... }
catch (InvalidPersonException e) { ... }
к
try { ... }
catch (Exception e) { ... }
Удачи!
Первый сохраняет трассировку стека, а второй сбрасывает ее. Это означает, что если вы используете второй подход, трассировка стека исключения всегда будет начинаться с этого метода, и вы потеряете исходную трассировку исключения, что может иметь катастрофические последствия для читателя журналов исключений, поскольку он никогда не узнает исходную причину исключения. .
Второй подход может быть полезен, когда вы хотите добавить дополнительную информацию в трассировку стека, но он используется следующим образом:
try
{
// do something
}
catch (Exception ex)
{
throw new Exception("Additional information...", ex);
}
Там в блоге после обсуждения различий.
throw
против throw e
.
Вы должны использовать
try { }
catch(Exception e)
{ throw }
если вы хотите что-то сделать с исключением перед его повторным выбросом (например, ведение журнала). Одинокий бросок сохраняет след стека.
Разница между catch без параметров и a в catch(Exception e)
том, что вы получаете ссылку на исключение. Начиная с версии платформы 2, неуправляемые исключения заключены в управляемое исключение, поэтому исключение без параметров больше ни для чего не используется.
Разница между throw;
и throw e;
заключается в том, что первая используется для повторной генерации исключений, а вторая - для создания вновь созданного исключения. Если вы используете второй для повторной генерации исключения, он будет рассматривать его как новое исключение и заменять всю информацию стека из того места, где оно было первоначально создано.
Таким образом, вы не должны использовать ни одну из альтернатив в вопросе. Вы не должны использовать catch без параметров, и вы должны использовать его throw;
для повторной генерации исключения.
Кроме того, в большинстве случаев для всех исключений следует использовать более конкретный класс исключения, чем базовый класс. Вы должны улавливать только те исключения, которые ожидаете.
try {
...
} catch (IOException e) {
...
throw;
}
Если вы хотите добавить какую-либо информацию при повторной генерации исключения, вы создаете новое исключение с исходным исключением в качестве внутреннего исключения, чтобы сохранить всю информацию:
try {
...
} catch (IOException e) {
...
throw new ApplicationException("Some informative error message", e);
}