Сведения о вопросе

Fedya

00:24, 9th August, 2020

Теги

exception    

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

Просмотров: 353   Ответов: 15

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



  Сведения об ответе

P_S_S

02:22, 22nd August, 2020

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

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

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

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

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

или это в Python году:

try:
    something()
except:
    pass

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

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


  Сведения об ответе

+-*/

23:10, 19th August, 2020

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

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

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


  Сведения об ответе

#hash

08:19, 8th August, 2020

Да! (за исключением "top" вашего заявления)

Перехватив исключение и позволив продолжить выполнение кода, Вы заявляете, что знаете, как справиться с конкретной проблемой, обойти ее или устранить. Вы утверждаете, что это вполне поправимая ситуация . Перехват исключения или SystemException означает, что вы будете ловить такие проблемы, как IO ошибок, сетевые ошибки, out-of-memory ошибок, Ошибки пропущенного кода, null-pointer-dereferencing и тому подобные. Это ложь-говорить, что вы можете справиться с ними.

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

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


  Сведения об ответе

P_S_S

00:55, 18th August, 2020

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

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


  Сведения об ответе

qwerty101

22:01, 18th August, 2020

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


  Сведения об ответе

lourence

21:17, 28th August, 2020

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

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


  Сведения об ответе

ЯЯ__4

23:14, 10th August, 2020

Я думаю, дело тут в двух вещах.

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

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


  Сведения об ответе

PHPH

18:52, 20th August, 2020

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

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

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

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

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

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


  Сведения об ответе

dumai

22:48, 7th August, 2020

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


  Сведения об ответе

piter

20:17, 29th August, 2020

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

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

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

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


  Сведения об ответе

SEEYOU

20:21, 4th August, 2020

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


  Сведения об ответе

KOMP

21:51, 9th August, 2020

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


  Сведения об ответе

9090

06:14, 3rd August, 2020

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

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


  Сведения об ответе

DINO

22:19, 26th August, 2020

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

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

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

До:

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


  Сведения об ответе

fo_I_K

00:29, 20th August, 2020

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

Ловите все ошибки, которые вы можете осмысленно исправить. Иногда это все они.

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

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться