Что такое "исключительный"?

Я ищу определение "исключительный" с точки зрения модульного тестирования или принципов ООП. Несколько раз, когда я говорил об исключении, я видел комментарии вроде: "Ну, я бы не стал считать Foo из Bar исключительным". (Есть ли смайлик троллинга?)

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


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

Ответ 1

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

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

Ответ 2

Исключительно, если:

  • Это условие отказа. И

  • Это происходит нечасто и неожиданно. И

  • Нет лучшего механизма для сообщая об этом.

изменить

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

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

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

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

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

Ответ 3

Общее эмпирическое правило:

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

Ответ 4

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

Ответ 5

Лично я считаю, что такая дискуссия - это пустая трата времени и что "что является исключительным" - это неправильный вопрос.

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

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

Ответ 6

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

Ответ 7

Ну, исключительный случай программирования - это тот, который отклоняет поток программы от обычного потока, и это может быть связано с:

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

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

Это слишком круто?: D

Ответ 8

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

Один пример - контейнеры С++, которые могут бросать bad_alloc, если они не могут получить нужную им память. Люди, которые писали контейнер, понятия не имеют, что должно произойти, если контейнер не может получить память. Возможно, это ожидаемая вещь, а код вызова имеет альтернативы. Возможно, это можно восстановить. Возможно, это фатально, но как его регистрировать?

Да, возможно передать коды ошибок, но будут ли они использоваться? Я вижу много распределений памяти C без тестов для NULL и printfs, которые просто отбрасывают возвращаемое значение. Более того, многие функции не имеют отличимого кода ошибки, такого как отрицательный для printf и NULL для выделения памяти. Если какое-либо возвращаемое значение может быть действительным, необходимо найти способ вернуть сообщение об ошибке, и это приведет к большему усложнению, чем большинство программистов готовы иметь дело. Исключение нельзя игнорировать и не требует много защитного кода.

Ответ 9

Лучшее обсуждение этого, что я видел, находится в блоге Дэна Вайнреба: Какие условия (исключения) действительно о.

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

Ответ 10

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

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

Пример плохого кода:

float x;
try {
x = a / b;
{
catch (System.DivideByZeoException) {
x = 0;
}

Хороший пример кода:

if (b == 0)
return 0;

Исключения обычно дороги.

Ответ 11

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

Oracle, в контексте Java, определяет исключительное событие таким образом:

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

Конечно, это определение относится к исключениям вообще, а не только к Java.

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

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

Я считаю, что есть два вида исключений:

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

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

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

Ответ 12

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

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

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

Ответ 13

Два основных случая:

  • При вызове кода вы просили сделать что-то необоснованное.
  • Когда внешние зависимости не оставили вам ничего разумного делать.

В первом случае рассмотрим метод int IntegerDivide(int dividend, int divisor). Теперь мы все знаем, что мы должны ловить такие условия, как деление на нуль. Однако, если вызывающий код попросил этот метод делить на ноль, он слишком поздно - это не наш код, который решает разделить на ноль, это вызывающий код. Единственное разумное предложение - выбросить исключение.

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