Неужели так плохо поймать общее исключение? - PullRequest
49 голосов
/ 22 августа 2008

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

Ответы [ 15 ]

85 голосов
/ 22 августа 2008

Очевидно, что это один из тех вопросов, где единственный реальный ответ - «это зависит».

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

Причина этого в том, что, например, Вы не хотите перехватывать все исключения в библиотеке, потому что вы можете маскировать проблемы, которые не имеют ничего общего с вашей библиотекой, такие как «OutOfMemoryException», которые вы бы действительно предпочли всплыть, чтобы пользователь мог получать уведомления и т. д. С другой стороны С другой стороны, если вы говорите о перехвате исключений внутри вашего метода main (), который перехватывает исключение, отображает его и затем завершает работу ... хорошо, вероятно, здесь можно отловить практически любое исключение.

Самым важным правилом перехвата всех исключений является то, что вы никогда не должны просто молча проглатывать все исключения ... например как то в Java:

try { 
    something(); 
} catch (Exception ex) {}

или это в Python:

try:
    something()
except:
    pass

Потому что это могут быть одни из самых сложных вопросов для отслеживания.

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

23 голосов
/ 22 августа 2008

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

Мое основное правило - перехватывать все ожидаемые исключения, а все остальное - ошибка.

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

15 голосов
/ 22 августа 2008

Да! (кроме как в верхней части вашего приложения)

Улавливая исключение и позволяя продолжить выполнение кода, вы заявляете, что знаете, как справиться с проблемой и обойти ее, или исправить конкретную проблему. Вы заявляете, что это исправимая ситуация . Catching Exception или SystemException означает, что вы будете обнаруживать такие проблемы, как ошибки ввода-вывода, сетевые ошибки, ошибки нехватки памяти, ошибки отсутствующего кода, разыменование нулевого указателя и тому подобное. Ложно сказать, что вы можете справиться с этим.

В хорошо организованном приложении эти неустранимые проблемы должны обрабатываться высоко в стеке.

Кроме того, по мере развития кода вы не хотите, чтобы ваша функция перехватывала новое исключение, которое будет добавлено в будущем к вызываемому методу.

11 голосов
/ 22 августа 2008

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

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

7 голосов
/ 22 августа 2008

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

3 голосов
/ 22 августа 2008

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

Чтобы привести один пример, в одном проекте я реализовал тип исключения, называемый CriticalException. Это указывает на состояние ошибки, которое требует вмешательства разработчиков и / или административного персонала, в противном случае клиенты получают неверный счет или могут возникнуть другие проблемы с целостностью данных. Он также может быть использован в других подобных случаях, когда просто регистрировать исключение недостаточно, и необходимо отправить оповещение по электронной почте.

Другой разработчик, который неправильно понимал концепцию исключений, затем обернул некоторый код, который потенциально может вызвать это исключение, в общий блок try ... catch, который отбросил все исключения. К счастью, я заметил это, но это могло привести к серьезным проблемам, особенно из-за того, что «очень необычный» угловой случай, который он должен был поймать, оказался гораздо более распространенным, чем я ожидал.

Таким образом, в общем, перехват общих исключений плох, если вы не уверены на 100%, что точно знаете , какие исключения будут выбрасываться и при каких обстоятельствах. Если вы сомневаетесь, пусть они всплывают в обработчике исключений верхнего уровня.

Подобное правило здесь никогда не выбрасывает исключения типа System.Exception. Вы (или другой разработчик), возможно, захотите перехватить ваше конкретное исключение выше стека вызовов, позволяя другим проходить через него.

(Однако есть один момент, на который следует обратить внимание. В .NET 2.0, если поток встречает какие-либо неперехваченные исключения, он выгружает весь домен приложения. Так что вы должны заключить основное тело потока в общую попытку ... catch заблокируйте и передайте все исключения, обнаруженные там, в ваш глобальный код обработки исключений.)

3 голосов
/ 22 августа 2008

Я думаю, что дело двоякое.

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

Во-вторых, руководящие принципы FxCop сосредоточены на коде Библиотеки / Framework - не все их правила предназначены для применения на веб-сайтах EXE или ASP.Net. Поэтому хорошо иметь глобальный обработчик исключений, который будет регистрировать все исключения и красиво выходить из приложения.

3 голосов
/ 22 августа 2008

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

В заключение вы поймаете как IOException, так и NullPointerException с помощью общего Exception, но способ, которым ваша программа должна реагировать, вероятно, отличается.

2 голосов
/ 26 января 2015

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

1 голос
/ 09 февраля 2018

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

Второе, однако, состоит в том, чтобы остановить прерывание вашей программы, когда она может продолжаться. Эти случаи:

  • Верх всех потоков (по умолчанию исключения исчезают без следа!)
  • Внутри основного цикла обработки, который, как вы ожидаете, никогда не выйдет
  • Внутри цикла, обрабатывающего список объектов, где один сбой не должен останавливать другие
  • Начало «основного» потока. Здесь вы можете контролировать сбой, например выгрузить немного данных в стандартный вывод, когда у вас закончится память.
  • Если у вас есть «Runner», который запускает код (например, если кто-то добавляет слушателя к вам и вы вызываете слушателя), то когда вы запускаете код, вы должны поймать Exception, чтобы зарегистрировать проблему и позволить вам продолжать уведомлять других слушателей.

В этих случаях вы ВСЕГДА хотите перехватить Exception (может быть, даже Throwable иногда), чтобы перехватывать программные / непредвиденные ошибки, регистрировать их и продолжать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...