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

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

404
задан 7 revs, 7 users 62% 28 November 2014 в 12:47
поделиться

30 ответов

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

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

Пример 2: скажите, что у меня есть другая функция, которая исследует List<> и возвращает true, если его длина - больше чем 50 и ложь, если длина меньше. Эта функция задает вопрос, "Этот список имеет больше чем 50 объектов?" Но этот вопрос делает предположение - он предполагает, что объект, который он дан, является списком. Если я вручаю ему ПУСТОЙ УКАЗАТЕЛЬ, то то предположение является ложью. В этом случае, если функция возвращается или верный или ложь, то это нарушает свои собственные правила. Функция не может возвратиться ничто и утверждать, что ответила на вопрос правильно. Таким образом, это не возвращается - это выдает исключение.

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

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

589
ответ дан 2 revs 28 November 2014 в 12:47
поделиться

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

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

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

0
ответ дан Mike Kantor 28 November 2014 в 12:47
поделиться

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

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
0
ответ дан Crusty 28 November 2014 в 12:47
поделиться

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

1
ответ дан Genjuro 28 November 2014 в 12:47
поделиться

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

В Вашем случае, если метод как Вход в систему (имя пользователя, пароль) вызывается, если имя пользователя не допустимо, это действительно корректно для броска 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))
    { }
}

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

Вот пример избегания использования Исключений в сценарии, любят просто описанный, с помощью Попытки () шаблон:

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;
    }
}
1
ответ дан 9 revs 28 November 2014 в 12:47
поделиться

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

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

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

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

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

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

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

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

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

2
ответ дан 2 revs, 2 users 97% 28 November 2014 в 12:47
поделиться

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

2
ответ дан Dan 28 November 2014 в 12:47
поделиться

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

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

3
ответ дан dclaysmith 28 November 2014 в 12:47
поделиться

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

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

23
ответ дан Bjorn Reppen 28 November 2014 в 12:47
поделиться

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

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

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

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

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

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

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

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

10
ответ дан Robert 28 November 2014 в 12:47
поделиться

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

РЕДАКТИРОВАТЬ: мне не нравится использовать исключения, потому что вы не можете сказать, если метод выдает исключение, просто посмотрев на вызов. Вот почему исключения следует использовать только в том случае, если вы не можете справиться с ситуацией достойным образом (подумайте «недостаточно памяти» или «компьютер горит»).

34
ответ дан 2 revs 28 November 2014 в 12:47
поделиться

Мои небольшие инструкции являются в большой степени под влиянием замечательной книги "Завершенным кодом":

  • исключения Использования для уведомления о вещах, которые не должны быть проигнорированы.
  • не используют исключения, если ошибка может быть обработана локально
  • , Удостоверяются, что исключения на том же уровне абстракции как остальная часть Вашей стандартной программы.
  • Исключения должны быть зарезервированы для того, что является действительно исключительно .
61
ответ дан 2 revs, 2 users 83% 28 November 2014 в 12:47
поделиться

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

-1
ответ дан yogman 28 November 2014 в 12:47
поделиться

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

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

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

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

Hope это помогает

1
ответ дан Michael 28 November 2014 в 12:47
поделиться

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

2
ответ дан Joe Skora 28 November 2014 в 12:47
поделиться

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

1
ответ дан anon 28 November 2014 в 12:47
поделиться

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

Так, короткий ответ - то, что, если это не вызывает значительную потерю производительности (который это не должно, если Вы не выдаете много исключений), затем идите вперед.

5
ответ дан Charles Graham 28 November 2014 в 12:47
поделиться

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

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

1
ответ дан Arno 28 November 2014 в 12:47
поделиться

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

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

0
ответ дан Serhat Ozgel 28 November 2014 в 12:47
поделиться

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

void f1() throws ExceptionType1, ExceptionType2 {}

void catchFunction() {
  try{
    while(someCondition){
      try{
        f1(); 
      }catch(ExceptionType2 e2){
        //do something, don't break the loop
      }
    }
  }catch(ExceptionType1 e1){
    //break the loop, do something else
  }

}

-1
ответ дан Sam 28 November 2014 в 12:47
поделиться

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

  • , Кто называет Ваш код? Действительно ли это - общедоступный какой-то API или внутренняя библиотека?
  • , Какой язык Вы используете? Если это - Java, например, то бросок (проверенного) исключения помещает явную нагрузку на Вашу вызывающую сторону для обработки этого состояния ошибки в некотором роде, в противоположность статусу возврата, который мог быть проигнорирован. Это могло быть хорошо или плохо.
  • , Как другие состояния ошибки в том же приложении обработаны? Вызывающие стороны не захотят иметь дело с модулем, который обрабатывает ошибки особенным способом в отличие от чего-либо еще в системе.
  • , Сколько вещей может пойти не так, как надо с рассматриваемой стандартной программой, и как они были бы обработаны по-другому? Рассмотрите различие между серией блоков выгоды, которые обрабатывают различные ошибки и переключатель на коде ошибки.
  • у Вас есть структурированная информация об ошибке, которую необходимо возвратить? Выдача исключения дает Вам лучшее место для помещения этой информации, чем просто возврат состояния.
0
ответ дан eli 28 November 2014 в 12:47
поделиться

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

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

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

Вот достойная начальная точка для исключений в.NET: http://msdn.microsoft.com/en-us/library/ms229030 (По сравнению с 80) .aspx

1
ответ дан Sam 28 November 2014 в 22:47
поделиться

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

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

16
ответ дан Mitchel Sellers 28 November 2014 в 22:47
поделиться

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

25
ответ дан japollock 28 November 2014 в 22:47
поделиться

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

277
ответ дан 2 revs, 2 users 67% 28 November 2014 в 22:47
поделиться

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

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

5
ответ дан Shachar 28 November 2014 в 22:47
поделиться

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

<час>

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

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

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

  • Предварительные условия, постусловия и инварианты характеристики дизайна нашей программы (ее внутренний API), тогда как решение к throw является деталью реализации. Это вынуждает нас принять во внимание, что мы должны рассмотреть дизайн и его реализацию отдельно и наше задание, в то время как реализация метода должна произвести что-то, что удовлетворяет конструктивные ограничения.
  • Это вынуждает нас думать с точки зрения предварительных условий, постусловий и инвариантов, которые являются только предположения, что вызывающие стороны нашего метода должны сделать, и выражаются точно, включая слабую связь между компонентами нашей программы.
  • , Что слабая связь затем позволяет нам осуществлять рефакторинг реализацию при необходимости.
  • постусловия и инварианты являются тестируемыми; это приводит к коду, который может быть легко протестированной единицей, потому что постусловия являются предикатами, которые может проверить наш код модульного теста (утверждают).
  • Взгляды с точки зрения постусловий естественно производят дизайн, который имеет успех как постусловие , который является естественным стилем для использования исключений. Нормальный ("счастливый") путь выполнения Вашей программы размечается линейно со всем кодом обработки ошибок, перемещенным в эти catch пункты.
14
ответ дан 2 revs, 2 users 89% 28 November 2014 в 22:47
поделиться

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

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

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

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

2
ответ дан Gord 28 November 2014 в 22:47
поделиться

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

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

2
ответ дан Jason Etheridge 28 November 2014 в 22:47
поделиться

На мой взгляд, фундаментальный вопрос должен заключаться в том, можно ли ожидать, что вызывающая сторона захочет продолжить нормальный ход программы, если возникнет условие. Если вы не знаете, то либо имейте отдельные методы 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() выбрасывала исключение, если команда не прошла.

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

1
ответ дан 22 November 2019 в 23:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: