Неужели так плохо поймать общее исключение?

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

22.08.2008 07:41:13
Если ввод непредсказуем, и сбой не является вариантом - это единственный способ. Конечно, нет веской причины не регистрировать ошибку, чтобы она могла быть исправлена ​​в следующий раз.
mehtunguh 2.12.2012 01:59:54
Это вопрос, который лучше подходит для programmers.stackexchange ?
HardcoreBro 22.11.2013 16:13:44
Мне нравится, что это также называется « Поймай покемонов - поймай их всех ».
Uwe Keim 16.08.2016 06:54:55
15 ОТВЕТОВ
РЕШЕНИЕ

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

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

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

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

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

или это в Python:

try:
    something()
except:
    pass

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

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

97
27.10.2011 18:44:25
Уловка всех исключений на границах языка для их перевода также является хорошей практикой.
Alexandre C. 3.08.2011 16:12:30
«Причина этого в том, что, например, вы не хотите перехватывать все исключения в библиотеке, потому что вы можете маскировать проблемы, которые не имеют ничего общего с вашей библиотекой, например,« OutOfMemoryException ».« Самое смешное, что платформа .NET фактически перехватывает OutOfMemoryExceptionиногда.
jrh 11.06.2018 17:29:39

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

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

4
20.02.2019 03:18:10

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

0
22.08.2008 08:45:57

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

0
22.08.2008 08:49:17

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

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

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

26
22.08.2008 08:50:14

Дело двоякое, я думаю.

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

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

3
22.08.2008 08:52:06
Плохо кодировать логику с помощью исключений, если вы ожидаете, что файл, предоставленный пользователем, не может существовать, есть метод для проверки: File.exists ().
Krzysztof Cichocki 27.06.2016 11:02:07
@KrzysztofCichocki - я знаю, что это старый, но на самом деле, кодирование файловой логики с использованием исключений таким способом является более правильным. Там отличное объяснение Эрик Липперт здесь . Он называет этот тип «экзогенными» исключениями.
Olly 4.07.2017 15:35:06
+1 за ответ от @Olly: Вы не можете проверить, существует ли файл заранее. Всегда есть условие гонки, где его можно удалить, прежде чем вы получите к нему доступ.
Jonas Benz 8.10.2019 07:39:20

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

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

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

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

15
22.08.2008 08:59:54
Поймать можно было бы добавить дополнительную информацию и затем выбросить, верно?
Maarten Bodewes 7.09.2016 14:50:14

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

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

11
22.08.2008 09:02:18

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

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

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

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

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

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

3
22.08.2008 09:50:36
Что произойдет, если код, который вызвал CriticalExceptionтакже называется Thread.Abort(Thread.CurrentThread)? Поскольку прерываемый поток будет в известном состоянии (вызов Abort), обычные опасности этого метода не будут применяться; код, который делает a catch(Exception ex), перехватит результирующее исключение прерывания потока, но не остановит его распространение по цепочке вызовов. Конечно, было бы лучше, если бы существовало какое-то иное поведение с более осмысленным именем, но я не знаю такой возможности в .NET.
supercat 6.12.2013 23:24:45

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

8
22.08.2008 12:47:44
Если всплыть исключение, это не означает, что оно будет показано конечному пользователю. Вы можете (и должны) показать общую страницу ошибок, зарегистрировать ее для расследования, а затем исправить проблему, которая вызвала исключение.
jammycakes 20.04.2009 08:52:20
Не отвечает на заданный вопрос.
Kenneth K. 12.02.2016 13:47:24

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

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

0
4.06.2014 08:21:05

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

2
26.01.2015 18:59:28

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

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

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

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

1
8.02.2018 21:33:14

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

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

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

Перед:

    catch (final RemoteException exc)
    {
        exc.printStackTrace();
    }
    catch (final IntentSender.SendIntentException exc)
    {
        exc.printStackTrace();
    }
    catch (final IabHelper.IabAsyncInProgressException exc)
    {
        exc.printStackTrace();
    }
    catch (final NullPointerException exc)
    {
        exc.printStackTrace();
    }
    catch (final IllegalStateException exc)
    {
        exc.printStackTrace();
    }

После:

    catch (final Exception exc)
    {
        exc.printStackTrace();
    }
0
15.11.2018 22:46:29

Непопулярное мнение: не совсем.

Поймайте все ошибки, которые вы можете существенно исправить. Иногда это все из них.

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

Имейте в виду, что некоторые исключения должны всплывать почти во всех случаях, например, в Python KeyboardInterruptи SystemExit. К счастью для Python, они хранятся в отдельной ветви иерархии исключений, поэтому вы можете позволить им всплыть, перехватывая Exception. Хорошо продуманная иерархия исключений делает этот тип вещей действительно простым.

Основное время перехвата общих исключений будет вызывать серьезные проблемы, когда имеешь дело с ресурсами, которые необходимо очистить (возможно, в finallyпредложении), поскольку обработчик универсальных действий может легко пропустить подобные вещи. К счастью, это не проблема для языков с deferтакими конструкциями, как Python withили RAII в C ++ и Rust.

1
6.02.2019 22:26:19