Когда выбросить исключение?

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

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

любые рекомендации или рекомендации по созданию исключений?

30 ответов


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

Пример 1: скажем, у меня есть функция, которая должна исследовать произвольный класс и возвращать true, если этот класс наследуется от List. Эта функция задает вопрос: "Является ли этот объект потомком списка?"Эта функция никогда не должна создавать исключения, потому что в ее работе нет серых областей - каждый отдельный класс либо делает, либо делает не наследуется от List, поэтому ответ всегда "да"или " нет".

Пример 2: скажем, у меня есть другая функция, которая проверяет список и возвращает true, если его длина больше 50, и false, если длина меньше. Эта функция задает вопрос: "имеет ли этот список более 50 элементов?"Но этот вопрос делает предположение-он предполагает, что объект, который он дает, является списком. Если я передаю ему NULL, то это предположение ложно. В этом случае, если функция возвращает или правда или false, то он нарушает свои собственные правила. Функция не может вернуть что-нибудь и утверждают, что он правильно ответил на вопрос. Поэтому он не возвращается - он создает исключение.

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

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


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


мои маленькие рекомендации находятся под сильным влиянием великой книги "Код завершен":

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

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

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


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


другие предлагают, чтобы исключения не использовались, потому что плохой логин следует ожидать в нормальном потоке, если пользователь ошибается. Я не согласен и не понимаю причины. Сравните это с открытием файла.. если файл не существует или недоступен по какой-либо причине, платформа создаст исключение. Используя логику выше, это было ошибкой Microsoft. Они должны были вернуть код ошибки. То же самое для синтаксического анализа, webrequests и т. д., п..

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


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

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


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


вы увидите множество советов, в том числе в ответах на этот вопрос, что вы должны бросать исключения только в "исключительных" обстоятельствах. Это кажется внешне разумный, но ошибочный совет, потому что он заменяет один вопрос ("когда я должен выбросить исключение") другим субъективным вопросом ("что является исключительным"). Вместо этого следуйте советам Herb Sutter (для C++, доступных в статья доктора Доббса когда и как использовать исключения, а также в своей книге с Андреем Александреску, Стандарты Кодирования C++): исключение, если и только если

  • предварительное условие не met (что обычно делает одно из следующих невозможно) или
  • альтернатива не будет соответствовать пост-условию или
  • альтернатива не сможет поддерживать инвариант.

почему это лучше? Разве это не заменяет вопрос несколько вопросы о предварительных условиях, постусловиях и инвариантах? Это лучше по нескольким взаимосвязанным причинам.

  • предусловия, постусловия и инварианты are конструкция характеристики нашей программы (ее внутренний API), тогда как решение throw - это деталь реализации. Это заставляет нас иметь в виду, что мы должны рассматривать дизайн и его реализацию отдельно, и наша работа при реализации метода заключается в создании чего-то, что удовлетворяет проектным ограничениям.
  • это заставляет нас думать в терминах предусловий, постусловий и инвариантов, которые являются только предположения, что абоненты из нашего метода следует сделать, и выражены точно, что позволяет свободные связи между компонентами нашей программы.
  • что то слабое связывание позволяет выполнить рефакторинг реализации, в случае необходимости.
  • пост-условия и инварианты проверяемы; это приводит к коду, который может быть легко проверен блоком, потому что пост-условия являются предикатами наш код модульного теста может проверять (утверждать).
  • мышление в терминах пост-условий, естественно, производит конструкция успех как пост-условие, который является естественным стилем для использования исключений. Обычный ("счастливый") путь выполнения вашей программы выложен линейно, при этом весь код обработки ошибок перемещен в catch положения.

Я бы сказал, что нет жестких и быстрых правил, когда использовать исключения. Однако есть веские причины использовать или не использовать их:

причины использования исключений:

  • поток кода для общего случая более ясен
  • может возвращать сложную информацию об ошибке в качестве объекта (хотя это также может быть достигнуто с помощью параметра error "out", переданного по ссылке)
  • языки вообще обеспечивают некоторое средство для управлять аккуратной уборкой внутри событие исключения (try/finally in Java, using in C#, RAII in C++)
  • в случае, если исключение не создается, выполнение может иногда быть быстрее, чем проверка кодов возврата
  • в Java проверенные исключения должны быть объявлены или пойманы (хотя это может быть причиной против)

причины не использовать исключения:

  • иногда это перебор, если обработка ошибок очень проста
  • Если исключения не документированные или объявленные, они могут быть не перехвачены вызывающим кодом, что может быть хуже, чем если вызывающий код просто проигнорировал код возврата (выход приложения против молчаливого отказа - что хуже может зависеть от сценария)
  • в C++ код, который использует исключения, должен быть безопасным для исключений (даже если вы не бросаете или ловите их, но вызываете функцию метания косвенно)
  • в C++ трудно сказать, когда функция может бросить, поэтому вы должны быть параноиком о безопасности исключений если вы используете их
  • исключения метания и ловли, как правило, значительно дороже по сравнению с проверкой флага возврата

В общем, я был бы более склонен использовать исключения в Java, чем в C++ или C#, потому что я считаю, что исключение, объявленное или нет, является фундаментальной частью формального интерфейса функции, так как изменение вашей гарантии исключения может нарушить вызывающий код. Самое большое преимущество использования их в Java IMO заключается в том, что вы знаете, что вызывающий абонент должен обрабатывать исключение, и это повышает вероятность правильного поведения.

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

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


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

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


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

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


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

Я хотел бы добавить, не стесняйтесь бросать стандартное исключение. Если вы не собираетесь делать что-то" другое " (игнорировать, электронную почту, журнал, показывать, что twitter whale picture thingy и т. д.), то не беспокойтесь о пользовательских исключения.


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

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


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

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

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

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


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

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


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


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


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

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

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

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

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

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

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

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

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


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

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

неправильное имя пользователя не обязательно является ошибкой программы, но ошибкой пользователя...

вот достойная отправная точка для исключений внутри .ЧИСТЫЙ: http://msdn.microsoft.com/en-us/library/ms229030 (VS.80).aspx


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

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


У меня есть три типа условий, которые я ловлю.

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

  2. Исключение AppException. Обычно это исключение, которое вы обнаруживаете и бросаете в свой код. Другими словами, это те, которые вы ожидаете (файл не существует). Зарегистрируйте его, установите сообщение, и вперед вернуться на страницу общие ошибки. На этой странице обычно есть немного информации о том, что произошло.

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

надеюсь, что это помогает


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


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

в вашем случае, если вызывается такой метод, как Login(username, password), если имя пользователя недопустимо, действительно правильно бросить UserNameNotValidException или PasswordNotCorrectException, если пароль неверен. Пользователь не может войти в систему с помощью предоставленных параметров (т. е. это невозможно, потому что это нарушит аутентификацию), поэтому создайте исключение. Хотя, возможно, Ваши два исключения унаследуют Исключение ArgumentException.

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

{ // class
    ...

    public LoginResult Login(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            return new UserInvalidLoginResult(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            return new PasswordInvalidLoginResult(user, password);
        }
        else
        {
            return new SuccessfulLoginResult();
        }
    }

    ...
}

public abstract class LoginResult
{
    public readonly string Message;

    protected LoginResult(string message)
    {
        this.Message = message;
    }
}

public class SuccessfulLoginResult : LoginResult
{
    public SucccessfulLogin(string user)
        : base(string.Format("Login for user '{0}' was successful.", user))
    { }
}

public class UserInvalidLoginResult : LoginResult
{
    public UserInvalidLoginResult(string user)
        : base(string.Format("The username '{0}' is invalid.", user))
    { }
}

public class PasswordInvalidLoginResult : LoginResult
{
    public PasswordInvalidLoginResult(string password, string user)
        : base(string.Format("The password '{0}' for username '{0}' is invalid.", password, user))
    { }
}

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

вот пример того, как избежать использования исключений в сценарии, как только что описано, используя шаблон Try ():

public class ValidatedLogin
{
    public readonly string User;
    public readonly string Password;

    public ValidatedLogin(string user, string password)
    {
        if (IsInvalidUser(user))
        {
            throw new UserInvalidException(user);
        }
        else if (IsInvalidPassword(user, password))
        {
            throw new PasswordInvalidException(password);
        }

        this.User = user;
        this.Password = password;
    }

    public static bool TryCreate(string user, string password, out ValidatedLogin validatedLogin)
    {
        if (IsInvalidUser(user) || 
            IsInvalidPassword(user, password))
        {
            return false;
        }

        validatedLogin = new ValidatedLogin(user, password);

        return true;
    }
}

на мой взгляд, основной вопрос должен заключаться в том, следует ли ожидать, что вызывающий абонент захочет продолжить нормальный поток программы, если возникает условие. Если вы не знаете, либо есть отдельные методы doSomething и trySomething, где первый возвращает ошибку, а последний-нет, или есть процедура, которая принимает параметр, чтобы указать, следует ли создавать исключение, если оно терпит неудачу). Рассмотрим класс для отправки команд в удаленную систему и отчетов об ответах. Определенный команды (например, перезапуск) заставят удаленную систему отправить ответ, но затем не будут реагировать в течение определенного периода времени. Таким образом, полезно иметь возможность отправить команду "ping" и узнать, отвечает ли удаленная система в разумный промежуток времени без необходимости создавать исключение, если это не так (вызывающий абонент, вероятно, ожидал бы, что первые несколько попыток "ping" потерпят неудачу, но в конечном итоге будет работать). С другой стороны, если имеется последовательность команд например:

  exchange_command("open tempfile");
  exchange_command("write tempfile data {whatever}");
  exchange_command("write tempfile data {whatever}");
  exchange_command("write tempfile data {whatever}");
  exchange_command("write tempfile data {whatever}");
  exchange_command("close tempfile");
  exchange_command("copy tempfile to realfile");

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

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


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


вы можете использовать немного общих исключений для этого условия. Например, ArgumentException предназначен для использования, когда что-то идет не так с параметрами метода (за исключением ArgumentNullException). Как правило, вам не нужны исключения, такие как LessThanZeroException, NotPrimeNumberException и т. д. Подумайте о пользователе вашего метода. Количество условий, которые она будет обрабатывать, будет равно количеству типов исключений, которые ваш метод нужно бросать. Таким образом, вы можете определить, насколько подробные исключения у вас будут.

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


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

  • кто вызывает ваш код? Это какой-то публичный API или внутренняя библиотека?
  • какой язык вы используете? Если это Java, например, то исключение (checked) накладывает явную нагрузку на вызывающего абонента для обработки этого условия ошибки каким-то образом, в отличие от состояния возврата, которое можно игнорировать. Это может быть хорошо или плохо.
  • как обрабатываются другие условия ошибок в том же приложении? Вызывающие абоненты не захотят иметь дело с модулем, который обрабатывает ошибки своеобразным способом, в отличие от всего остального в системе.
  • сколько вещей может пойти не так с рутиной в вопросе, и как бы они были по-другому? Рассмотрим разницу между серией блоков catch, которые обрабатывают различные ошибки, и переключателем кода ошибки.
  • у вас есть структурированная информация об ошибке, которую вам нужно вернуть? Исключение дает вам лучшее место для размещения этой информации, чем просто возврат статуса.

существует два основных класса исключений:

1) исключение системы (например, потерянное соединение с базой данных) или 2) исключения пользователей. (например, проверка ввода пользователем, "пароль неверен")

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

            If TypeName(ex) = "UserException" Then
               Display(ex.message)
            Else
               DisplayError("An unexpected error has occured, contact your help  desk")                   
               LogError(ex)
            End If

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

  1. какой уровень кода, который вы хотите запустить после выхода кандидата на исключение - то есть, сколько слоев стека вызовов следует расслабиться. Обычно требуется обработать исключение как можно ближе к месту его возникновения. Для проверки имени пользователя/пароля вы обычно обрабатываете сбои в одном блоке кода, а не позволяете исключению всплывать. Так исключение, вероятно, неуместно. (OTOH, после трех неудачных попыток входа в систему поток управления может переместиться в другое место, и здесь может быть уместно исключение.)

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


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

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

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

Итак, как правило:

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