Когда бросить исключение? - PullRequest
400 голосов
/ 17 сентября 2008

У меня есть исключения, созданные для каждого условия, которое мое приложение не ожидает. UserNameNotValidException, PasswordNotCorrectException и т. Д.

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

Любое руководство или лучшие практики для создания исключений?

Ответы [ 33 ]

5 голосов
/ 17 сентября 2008

Классы исключений похожи на "нормальные" классы. Вы создаете новый класс, когда он «является» объектом другого типа, с другими полями и различными операциями.

Как правило, вы должны попытаться найти баланс между количеством исключений и гранулярностью исключений. Если ваш метод генерирует более 4-5 различных исключений, вы, вероятно, можете объединить некоторые из них в более «общие» исключения (например, в вашем случае «AuthenticationFailedException») и использовать сообщение об исключении, чтобы подробно описать, что пошло не так. Если ваш код не обрабатывает каждый из них по-разному, вам не нужно создавать много классов исключений. И если это произойдет, пусть вы просто вернете перечисление с ошибкой, которая произошла. Так немного чище.

3 голосов
/ 17 сентября 2008

Я согласен с japollock, если вы не уверены в исходе операции. Вызовы API, доступ к файловым системам, вызовы базы данных и т. Д. Каждый раз, когда вы пересекаете «границы» ваших языков программирования.

Я хотел бы добавить, не стесняйтесь бросать стандартное исключение. Если вы не собираетесь делать что-то «другое» (игнорировать, отправлять по электронной почте, регистрировать, показывать, что твиттер изображает кита и т. Д.), То не беспокойтесь о пользовательских исключениях.

3 голосов
/ 19 декабря 2011

Практическое правило создания исключений довольно простое. Вы делаете это, когда ваш код вошел в НЕИЗВЕСТНОЕ НЕВЕРНОЕ состояние. если данные скомпрометированы или вы не можете свернуть обработку, которая произошла до этой точки, вы должны прекратить ее. действительно, что еще вы можете сделать? ваша логика обработки в конечном итоге потерпит неудачу в другом месте. если вы можете как-то восстановиться, сделайте это и не бросайте исключение.

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

2 голосов
/ 17 сентября 2008

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

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

2 голосов
/ 17 сентября 2008

Как правило, вы хотите создать исключение для всего, что может произойти в вашем приложении, которое является «Исключительным»

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

Они являются "исключениями" для основного потока вашего UML, но являются более "ветвями" в обработке.

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

2 голосов
/ 17 сентября 2008

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

2 голосов
/ 17 сентября 2008

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

2 голосов
/ 17 сентября 2008

Я бы сказал, что, как правило, каждый фундаментализм ведет в ад.

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

Обычно я предпочитаю создавать два основных типа исключений, которые используются во всей системе: LogicalException и TechnicalException . Их можно дополнительно различать по подтипам, если это необходимо, но обычно это не является необходимым.

Техническое исключение означает действительно неожиданное исключение, такое как отключение сервера базы данных, соединение с веб-службой, вызвало IOException и так далее.

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

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

Так что в примере входа в систему может быть целесообразно создать что-то вроде AuthenticationException и различать конкретные ситуации по значениям перечисления, таким как UsernameNotExisting , PasswordMismatch и т. Д. Тогда вы не получите иметь огромную иерархию исключений и может поддерживать блоки catch на поддерживаемом уровне. Вы также можете легко использовать некоторый общий механизм обработки исключений, так как вы классифицировали исключения и хорошо знаете, что распространять до пользователя и как.

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

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

1 голос
/ 17 сентября 2008

Безопасность связана с вашим примером: вы не должны сообщать злоумышленнику, что имя пользователя существует, но пароль неверный. Это дополнительная информация, которой вам не нужно делиться. Просто скажите «имя пользователя или пароль неверны».

1 голос
/ 17 сентября 2008

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

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

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