Какие и почему вы предпочитаете исключения или коды возврата? - PullRequest
72 голосов
/ 19 сентября 2008

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

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

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

Ответы [ 23 ]

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

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

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

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

Я использую исключения в python как в исключительных, так и в неисключительных обстоятельствах.

Часто приятно иметь возможность использовать Исключение, чтобы указать «запрос не может быть выполнен», а не возвращать значение «Ошибка». Это означает, что вы / всегда / знаете, что возвращаемое значение - правильный тип, а не произвольно None или NotFoundSingleton или что-то еще. Вот хороший пример того, где я предпочитаю использовать обработчик исключений вместо условного для возвращаемого значения.

try:
    dataobj = datastore.fetch(obj_id)
except LookupError:
    # could not find object, create it.
    dataobj = datastore.create(....)

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

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

# wrong way:
if os.path.exists(directory_to_remove):
    # race condition is here.
    os.path.rmdir(directory_to_remove)

# right way:
try: 
    os.path.rmdir(directory_to_remove)
except OSError:
    # directory didn't exist, good.
    pass

Один системный вызов вместо двух, никаких условий гонки. Это плохой пример, потому что очевидно, что это приведет к ошибке OSError в большем количестве случаев, чем отсутствие каталога, но это «достаточно хорошее» решение для многих строго контролируемых ситуаций.

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

При любых приличных исключениях для компилятора или среды выполнения значительное наказание не налагается. Это более или менее похоже на оператор GOTO, который переходит к обработчику исключений. Кроме того, наличие исключений, перехваченных средой выполнения (например, JVM), помогает намного легче изолировать и исправить ошибку. Я возьму исключение NullPointerException в Java вместо ошибки в C в любой день.

3 голосов
/ 27 октября 2017

Коды возврата не проходят тест " Pit of Success " для меня почти каждый раз.

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

Относительно производительности:

  • Исключения могут быть вычислительно дорогостоящими ОТНОСИТЕЛЬНО, чтобы вообще не выбрасывать, но по какой-то причине они называются ИСКЛЮЧЕНИЯМИ. Сравнения скорости всегда позволяют предположить, что уровень исключения составляет 100%, что никогда не должно иметь место. Даже если исключение в 100 раз медленнее, насколько это действительно важно, если это происходит только в 1% случаев?
  • Если мы не говорим о арифметике с плавающей запятой для графических приложений или о чем-то подобном, циклы ЦП обходятся дешевле, чем время разработчиков.
  • Стоимость с точки зрения времени имеет тот же аргумент. По сравнению с запросами к базе данных, вызовами веб-служб или загрузкой файлов обычное время приложения будет превышать время исключения. Исключения составляли почти субмикросекунды в 2006 году
    • Я осмелюсь всех, кто работает в .net, настроить ваш отладчик так, чтобы он работал со всеми исключениями, отключил только мой код и увидел, сколько исключений уже происходит, о которых вы даже не знаете.
2 голосов
/ 19 сентября 2008

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

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

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

  • Обычно для удобства читатели стараются свести к минимуму количество операторов возврата в методе. При этом исключения не позволяют выполнять дополнительную работу, когда они находятся в неправильном состоянии, и, таким образом, предотвращают потенциальное повреждение большего количества данных.
  • Исключения, как правило, более многословны и более легко расширяемы, чем возвращаемое значение. Предположим, что метод возвращает натуральное число и что вы используете отрицательные числа в качестве кода возврата при возникновении ошибки. Если область действия вашего метода изменится и теперь будет возвращать целые числа, вам придется изменить все вызовы метода вместо того, чтобы просто немного подправить исключение.
  • Исключения позволяют более легко отделить обработку ошибок от нормального поведения. Они позволяют гарантировать, что некоторые операции выполняются как атомарные операции.
2 голосов
/ 19 сентября 2008

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

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

if(function(call) != ERROR_CODE) {
    do_right_thing();
}
else {
    handle_error();
}

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

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

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

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

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

Я не считаю коды возврата менее уродливыми, чем исключения. За исключением, у вас есть try{} catch() {} finally {}, где, как и с кодами возврата, у вас есть if(){}. Раньше я боялся исключений по причинам, указанным в посте; Вы не знаете, нужно ли очищать указатель, что у вас. Но я думаю, что у вас есть те же проблемы, когда дело доходит до кодов возврата. Вы не знаете состояния параметров, если не знаете некоторые подробности о рассматриваемой функции / методе.

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

Мне нравится идея вернуть значение (перечисление?) Для результатов и исключение для исключительного случая.

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

У меня есть простой набор правил:

1) Используйте коды возврата для вещей, на которые, как вы ожидаете, отреагирует ваш непосредственный абонент.

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

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

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