Где вы любите ловить исключения и почему?

Где вы любите ловить исключения и почему?

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

Одно место и причина для каждого ответа, пожалуйста. Спасибо.

Опрос обязательно должен быть вики, если вы предоставляете варианты!

Greg 12.01.2009 12:04
Повышение качества Laravel с помощью принципов SOLID: Лучшие практики и примеры
Повышение качества Laravel с помощью принципов SOLID: Лучшие практики и примеры
Когда мы говорим о том, как сделать следующий шаг в качестве разработчика, мы должны понимать, что качество кода всегда является основным фокусом на...
Принципы SOLID - лучшие практики
Принципы SOLID - лучшие практики
SOLID - это аббревиатура, обозначающая пять ключевых принципов проектирования: принцип единой ответственности, принцип "открыто-закрыто", принцип...
9
1
2 223
9

Ответы 9

Я всегда помещаю уловку в 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.

Rob Kennedy 12.01.2009 12:42

В C# и Java я предпочитаю вообще не перехватывать исключения. Если я не могу этого избежать, я немедленно повторно генерирую исключение RunTime.

Я всегда буду использовать самый жадный блок catch, который имеет наибольшую необходимую область видимости, но всегда с наиболее конкретным возможным типом исключения. Поскольку результатом блока catch является еще один бросок в 99,99% случаев, я стараюсь сохранить полный метод в блоке try.

Два места:

  • Во всех обработчиках событий
  • Любое место, где уловка может сделать что-то полезное, например, дополнить исключение информацией, которая будет полезна для отладки. Обычно с этой информацией создается и выбрасывается новое исключение. Обратите внимание, что для InnerException (или эквивалента, отличного от .NET) этого нового исключения должно быть установлено значение исходного исключения, чтобы такие вещи, как трассировка стека, были сохранены.

Я стараюсь ловить ТОЛЬКО те исключения, с которыми могу справиться.

Я НЕНАВИЖУ такой код:

      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 автоматически откроет для вас отладчик. Вы ищете не точно, но поможет ли вам добраться туда? Оценил ваш ответ кстати.

GrahamMc 19.01.2011 18:50

Не ловите то, к чему вы не готовы и не способны справиться.

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

И вы должны сделать только одно из двух: на самом деле сделать что-то, чтобы решить / обойти проблему или повторно создать более описательное исключение, которое имеет пойманное исключение в качестве своего innerException.

Обновлено: если вам нужен блок finally (например, чтобы выпустить что-то, что вы выделили в своем коде), и вам нечего делать с любыми исключениями, которые могут появиться, применяется та же логика: просто не обрабатывайте их. Вместо этого используйте catch { throw; }, чтобы перебросить исключение на более высокий уровень, сохранив при этом всю информацию об исключении. (Или просто опустите блок catch, который, как я думаю / надеюсь, делает то же самое?)

О, это на C#, если вы не заметили. (То же самое и с другими языками .NET.)

peSHIr 12.01.2009 13:59

Мне нравится стараться, чтобы мой код обработки исключений был отделен от другого кода, поэтому я обычно создаю вспомогательный метод, который выполняет фактическую логику, а внешний метод занимается только обработкой исключений. Я всегда думал, что это придает коду чистый вид и делает его более читабельным.

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)
Что рекомендую:

  1. Найдите ближайшую точку в цепочке вызовов от источника исключения, где вы можете обработать исключение должным образом - например, принять меры по исправлению, сбой сигнала транзакции / действия и т. д. (Ведение журнала само по себе не должно рассматриваться как обработка исключений) Все методы между обработчиком и метателем следует игнорировать исключение. Предпочитайте непроверенные исключения отмеченным, чтобы исключения даже не фигурировали во всех этих промежуточных методах.
  2. Границы уровня и API-интерфейсы должны указывать исключения, которые он может генерировать с помощью проверенных исключений, поскольку обработка этих исключений является частью контракта для клиентского уровня / кода, который его использует.
  3. Напишите класс обработчика исключений с методом handle(Exception e) и сначала передайте его команде и убедитесь, что все используют его для обработки исключений. Основываясь на изменении сценариев обработки исключений, продолжайте добавлять перегруженные методы «дескриптора» позже, так что нужно будет изменять только обработчик.
  4. Всегда не забывайте связывать исключения при выполнении ловли и бросания. Это гарантирует, что будет сообщена полная причина исключения.
  5. Никогда не записывайте одну и ту же трассировку исключения более одного раза. Это очень затрудняет отладку с использованием файлов журнала.
  6. Методы верхнего уровня должны иметь предложение catch, которое перехватывает исключение любой, которое может генерировать система. Это предотвращает утечку нашей внутренней информации во внешний мир, если, не дай бог, что-то пойдет не так в производственной среде. Это скорее требование безопасности.

Другие вопросы по теме