Почему исключения должны использоваться консервативно? - PullRequest
77 голосов
/ 16 ноября 2009

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

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

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

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

Ответы [ 28 ]

1 голос
/ 16 ноября 2009

Допустимый случай для исключения:

  • Вы пытаетесь открыть файл, его там нет, выдается исключение FileNotFoundException;

Незаконное дело:

  • Вы хотите что-то сделать, только если файл не существует, вы пытаетесь открыть файл, а затем добавить некоторый код в блок catch.

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

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

RecordIterator<MyObject> ri = createRecordIterator();
try {
   MyObject myobject = ri.next();
} catch(NoSuchElement exception) {
   // Object doesn't exist, will create it
}

Это было бы лучше:

RecordIterator<MyObject> ri = createRecordIterator();
if (ri.hasNext()) {
   // It exists! 
   MyObject myobject = ri.next();
} else {
   // Object doesn't exist, will create it
}

КОММЕНТАРИЙ, ДОБАВЛЕННЫЙ К ОТВЕТУ:

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

Комментарии к этому могут добавить больше, чем сам мой ответ.

0 голосов
/ 22 ноября 2009

Мои два цента:

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

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

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

Для ParseInt, как упоминалось ранее, мне нравится идея исключений. Просто верните значение. Если параметр не может быть проанализирован, выдается исключение. Это делает ваш код чище с одной стороны. На уровне вызова вам нужно сделать что-то вроде

try 
{
   b = ParseInt(some_read_string);
} 
catch (ParseIntException &e)
{
   // use some default value instead
   b = 0;
}

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

int ParseIntWithDefault(String stringToConvert, int default_value=0)
{
   int result = default_value;
   try
   {
     result = ParseInt(stringToConvert);
   }
   catch (ParseIntException &e) {}

   return result;
}

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

  • исключения все еще должны быть где-то обработаны. Дополнительная проблема: c ++ не имеет синтаксиса, который позволяет ему определять, какие исключения может генерировать функция (как в java). Таким образом, вызывающий уровень не знает, какие исключения могут потребоваться для обработки.
  • иногда код может стать очень многословным, если каждая функция должна быть заключена в блок try / catch. Но иногда это все еще имеет смысл.

Так что иногда трудно найти хороший баланс.

0 голосов
/ 22 ноября 2009

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

0 голосов
/ 17 ноября 2009

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

Практически каждое правило программирования - это правило, гласящее: «Не делайте этого, если у вас нет действительно веской причины»: «Никогда не используйте goto», «Избегайте глобальных переменных», «Регулярные выражения заранее увеличивают количество ваших проблемы одним "и т. д. Исключения не являются исключением ....

0 голосов
/ 17 ноября 2009

Я использую исключения, если:

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

Если ошибка может быть восстановлена ​​из (пользователь ввел «яблоко» вместо числа), затем восстановите (запросите ввод еще раз, измените значение по умолчанию и т. Д.).

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

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

0 голосов
/ 16 ноября 2009

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

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

Я остановлюсь на другом моменте:

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

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

Так что вы закончите, элегантно сжигая свой процессор, не зная.

Итак: использовать исключения только в исключительных случаях - Значение: при возникновении реальных ошибок!

0 голосов
/ 16 ноября 2009

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

Исключения IMHO следует использовать, когда вы хотите обеспечить нормальное значение по умолчанию в случае, если вызывающий объект пренебрегает записать код обработки ошибки или если ошибку лучше всего обрабатывать дальше по стеку вызовов, чем непосредственный вызывающий. Разумным по умолчанию является выход из программы с разумным диагностическим сообщением об ошибке. Безумная альтернатива заключается в том, что программа хромает в ошибочном состоянии и в какой-то момент вылетает или молча выдает плохой результат, что затрудняет диагностику точки. Если «ошибка» является нормальной частью потока программы, чтобы вызывающая сторона не могла разумно забыть проверить ее, исключения не должны использоваться.

0 голосов
/ 16 ноября 2009

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

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

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

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