Где вы любите ловить исключения и почему? - PullRequest
9 голосов
/ 12 января 2009

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

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

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

Ответы [ 9 ]

10 голосов
/ 12 января 2009

Не поймай ничего, к чему ты не готов и не способен.

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

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

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

5 голосов
/ 12 января 2009

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

Я ненавижу код, подобный этому:

      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, я ловлю только те ошибки, которые могу обработать. И я с радостью бросаю необдуманные исключения, когда ввод не соответствует моим ожиданиям.

Идея в том, что я не хочу, чтобы ошибка регистрировалась или документировалась. Я хочу это исправить.

3 голосов
/ 12 января 2009

Я всегда ставлю улов в 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() );
    }
}
2 голосов
/ 12 января 2009

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

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

1 голос
/ 12 января 2009

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

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
}
0 голосов
/ 23 июня 2011

(Прежде чем я начну: я парень из Java)
Что я рекомендую:

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

В приложении Delphi для Windows основной цикл обработки сообщений для вашего приложения (то есть в нижней части стека вызовов) обрабатывает ваши исключения, показывая окно сообщения. На мой взгляд, это лучшее место для обработки исключений.

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

Я бы обработал исключение, только если:

  • Мне нужно выполнить некоторую очистку (например, откат БД), и в этом случае я бы вызвал исключение после очистки.
  • У меня есть еще информация, чтобы добавить к исключению.
  • Мой метод может преуспеть в своей цели, несмотря на исключение.
0 голосов
/ 12 января 2009

Два места:

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

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

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