Где вы любите ловить исключения и почему?
Мне интересно узнать, где люди считают полезным размещать свои блоки try / catch в надежде, что могут появиться какие-то общие закономерности. Я отправлю свои два примера ответов на C++, но любой язык подойдет.
Одно место и причина для каждого ответа, пожалуйста. Спасибо.


Я всегда помещаю уловку в main () как крайнюю уловку:
int main( int argc, char** argv ) {
try {
Application application( argc, argv );
return application.result();
}
catch ( const std::exception& exception ) {
fprintf( stderr, "%s.\n", exception.what() );
}
}
Мне нравится ловить обработчики в контроллере, которые обрабатывают события, запускаемые из представления. Если исключения дают надежную гарантию безопасности, это полезный момент, потому что он достаточно высокий, чтобы сообщить об ошибке, а обработчики обычно атомарны и связаны с чем-то, что только что сделал пользователь, поэтому, надеюсь, они смогут решить что происходит.
void Controller::on_edit_entity( const Entity& entity ) {
try {
Command::ptr command = new EditEntityCommand( entity );
push_command( command );
}
catch ( const std::exception& exception ) {
fprintf( stderr, "%s.\n", exception.what() );
}
}
Не заставляйте пользователя понять это. Если вы не можете ручка исключение - исправить любую проблему, вызвавшую его в первую очередь, - тогда не ловите его, иначе код не упадет, потому что он предполагает, что все в порядке, хотя на самом деле это не так. Например, ваш код перехватывает std :: bad_alloc.
В C# и Java я предпочитаю вообще не перехватывать исключения. Если я не могу этого избежать, я немедленно повторно генерирую исключение RunTime.
Я всегда буду использовать самый жадный блок catch, который имеет наибольшую необходимую область видимости, но всегда с наиболее конкретным возможным типом исключения. Поскольку результатом блока catch является еще один бросок в 99,99% случаев, я стараюсь сохранить полный метод в блоке try.
Два места:
Я стараюсь ловить ТОЛЬКО те исключения, с которыми могу справиться.
Я НЕНАВИЖУ такой код:
String s = "12";
Integer i;
try {
i = Integer.parseInt(s);
} catch(ParseException pe) {
System.out.println("hihihihihihihi!!!);
}
Что я особенно ненавижу, так это то, что это обычно приводит к прерыванию потока в любом случае, потому что тремя строками позже будет доступ к i, который будет предполагать, что i! = Null.
Затем вы прочитаете свою трассировку стека, прокрутите и прокрутите журнал, пока не найдете первую значительную ошибку, из-за которой все остальное развалилось.
Я бы хотел, чтобы Java не заставляла меня ловить исключения, с которыми я все равно не могу справиться. Но вот что я могу сделать:
catch(Exception e) {
throw new RuntimeException(e);
}
И я объявляю много «бросков» в своих определениях функций.
Я все еще мечтаю о том дне, когда Eclipse автоматически откроет отладчик в правильной строке, когда получит неперехваченное исключение. В этот день мой метод откроет правильную строку.
На других языках, таких как Smalltalk, я отлавливаю только те ошибки, с которыми могу справиться. И я с радостью выбрасываю неперехваченные исключения, когда ввод не соответствует моим ожиданиям.
Идея в том, что я не хочу, чтобы ошибка регистрировалась или документировалась. Я хочу это исправить.
Привет, nes1983 Не уверен, что вы знаете о stackoverflow.com/questions/3066199/… - что касается вашего комментария о том дне, когда Eclipse автоматически откроет для вас отладчик. Вы ищете не точно, но поможет ли вам добраться туда? Оценил ваш ответ кстати.
Не ловите то, к чему вы не готовы и не способны справиться.
Итак, иметь на месте обработку исключений верхнего уровня бомбардирует приложение неожиданными исключениями так, как вам нравится, а затем ловит только то, что вам нужно (как можно ближе к тому месту, где это может произойти), чтобы получить необходимую функциональность.
И вы должны сделать только одно из двух: на самом деле сделать что-то, чтобы решить / обойти проблему или повторно создать более описательное исключение, которое имеет пойманное исключение в качестве своего innerException.
Обновлено: если вам нужен блок finally (например, чтобы выпустить что-то, что вы выделили в своем коде), и вам нечего делать с любыми исключениями, которые могут появиться, применяется та же логика: просто не обрабатывайте их. Вместо этого используйте catch { throw; }, чтобы перебросить исключение на более высокий уровень, сохранив при этом всю информацию об исключении. (Или просто опустите блок catch, который, как я думаю / надеюсь, делает то же самое?)
О, это на C#, если вы не заметили. (То же самое и с другими языками .NET.)
Мне нравится стараться, чтобы мой код обработки исключений был отделен от другого кода, поэтому я обычно создаю вспомогательный метод, который выполняет фактическую логику, а внешний метод занимается только обработкой исключений. Я всегда думал, что это придает коду чистый вид и делает его более читабельным.
public void stuff() throws MyException
{
try
{
tryStuff();
}
catch (SomeLibraryException e)
{
logger.log("Some message happened", e);
throw new MyException(e);
}
}
public void tryStuff() throws SomeLibraryException
{
// Do things in here that could throw exceptions
}
В приложении Windows Delphi основной цикл обработки сообщений для вашего приложения (то есть в нижней части стека вызовов) обрабатывает ваши исключения, показывая окно сообщения. На мой взгляд, это лучшее место для обработки исключений.
Перехватывая исключения в ваших собственных методах с единственной целью показать пользователю окно сообщения, вы запрещаете любому коду, вызывающему ваш метод, знать, что исключение действительно произошло и что метод фактически не удался.
Я бы обработал исключение только в том случае, если:
(Прежде чем я начну: я парень Java)
Что рекомендую:
handle(Exception e) и сначала передайте его команде и убедитесь, что все используют его для обработки исключений. Основываясь на изменении сценариев обработки исключений, продолжайте добавлять перегруженные методы «дескриптора» позже, так что нужно будет изменять только обработчик.
Опрос обязательно должен быть вики, если вы предоставляете варианты!