Как стать автором
Обновить

Комментарии 50

Логичный вывод спасибо!..
Помнится в универе видел пример программы, построенной только на логике кидания исключений. Было весело)
улыбнуло, вот бы увидеть сам код — ржач на весь день будет)
Раньше был противником программирования через исключения.
Но в первом же большом проекте вывел для себя несколько плюсов:

  • Улучшает качество архитектуры.
  • Сокращает время разработки.
  • Более чистый и тем самым понятный код.
  • Повышает отказаустойчевость приложения.
  • «Улегчение» отладки.


Во всех своих проектах создаю классы исключений, которые за меня автоматически и без внесения изменения в код проделывают большенство записей в лог по разным параметрам. После этого 90% багов отлавливаются при чтении логов, и мне не приходится тратить время на нудный дебангинг.
Exception — это мечта программиста, это возможность побыть Оракулом: «заглянуть в будущее» и написать код в стиле «если выполнении этого кода когда-нибудь отвалится, то поправить это так и так».
Отсюда простое правило — если возникла ошибка, и код сам знает, как ее поправить, то исключение генерить не надо.

>>Exception`ы более медленный механизм, чем «код возврата ошибки»

Верно, а php еще более медленный, чем exception в C++. Давайте не юзать php и исключения, что ли?
Exception на то и «исключительная ситуация», чтобы происходить достаточно редко. Так что на производительность она оказывает минимальное влияние. Убирайте #3 в разделе pro :) Хотелось бы увидеть аргументированные цифры, насколько именно «проседает» производительность при использовании исключений (обращу внимание — в нормальном режиме, а не в «беличьем колесе» while с бешеным количеством throws/сeк.)

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

хмм… возникла идея, почему бы авторам, например, не делать вывод из всех комментов. тоесть в конце статьи добавить выдержку основных идей, мыслей итп. можно даже 2 точки зрения за и против к примеру.
Предположим вы вызываете некий метод некого класса: someClass.SomeMethod();
Вы не можете с уверенностью сказать, будет ли сгенерировано исключение.
Зависит от языка.
В яве, если вызываемый метод может сгенерить исключение, а вы его и не обрабатываете, и не передаёте выше — такой код даже не откомпилится: «Unhandled exception type SomeException».
Да, про Java я знаю, но я лучше знаю C#, что обусловило рамки данного топика.
Вот за это я не люблю джаву. Бывает множество ситуаций, когда я не хочу ловить все возможные исключения. Например, я пишу одноразовую программулину, которая должна прочитать данные из одного файла, что-то с ними сделать и записать в другой. Я знаю, что все данные правильные, а даже если что-то пойдет не так, меня вполне устроит аварийная остановка всей программы. Джава не дает мне возможности наплевать на возможные ошибки. Так что я за гибкость, которая есть в C++/C#.
что мешает в IDE сгенерить пустой try {} catch(Throwble e){}
Да ничего не мешает, в принципе. Но зачем принудительно засорять код?
Это не столько засорение кода, сколько ваша явная расписка перед компилятором: «В случае эксепшена, претензий не имею».
Исключения в java сделаны, чтобы их грамотно обрабатывали. Своим подходом в обработке исключений вы рубите на корню всю гениальную задумку разработчиков, как, к сожалению, делают и многие другие java-программисты:(
Давайте не будем выносить вердикты не разобравшись в сути проблемы. Мое предложение было высказано как альтернатива, но не как правило использования.
мне кажется, что чистые ООП-языки вообще для одноразовых задач не очень. Джава и Шарп проектировались для средних и больших проектов. Я одобряю консервативный подход комитета Джавы, и не одобряю подход в стиле «давайте запихнем всю круть в язык»

Для однострочников и разовых скриптов нужны скриптовые же языки вроде… Ну bash, python (ironpython), vb и все такое.
Исключения не дают себя проигнорировать случайно, имеют бОльшую информативность.
Насчёт того, что это медленный механизм, — это роли не играет, на то оно и исключение.
Ваш пример с потенциально неверными данными — это не исключение, это нормальная ситуация. Не кидать же исключение из метода, например, find.
Вы знаете, за свою практику я повидал столько, что волосы дыбом иногда становились.
Поповоду игнорирования — это смотря где, в той же Javе да, в C#, для десктоп, обычно, вываливается окошко, которое сообщает пользователю, что «что-то не то» случилось + расширенная инфа по исключению, это не есть хорошо, но такое встречается.
Про игнорирование я имел в виду, что исключение если вылетит, то обязательно где-то будет поймано, хотя бы рантаймом на самом верху. Т.е. поведение детерминированно.
Если же мы проигнорируем возвращаемое значение, то дальше может быть вообще неопределённое поведение, так как алгоритм на такое не закладывался.
Имхо, лучше упасть, даже с треском, чем потом выяснить, что не то и не туда сохранялось, а что-то вообще потёрлось, хотя зависит от, конечно.
...to trow new Exception or not to trow...
или я не прав?
Почти:)
...to throw new Exception or not to throw…
сори задумался… это все проклятый IntelliSense :)
НЛО прилетело и опубликовало эту надпись здесь
Если уж быть до конца честным, то исключения были придуманы задолго до ООП, сама концепция; и PL/I один из примеров тому. Затем с появлением ООП, они очень хорошо «вписались» в концепцию, став объектом того мира. Да и их распространение ставилось как «contro» к коду возврату ошибок.
Joel (в ответ на критику после первого поста про исключения — знаменитый 13) акцентирует внимание на том, что хороший, стабильный (в высших смыслах) код очень сложно написать без исключений, а с ними — в разы сложнее. Поэтому как вывод преподносит, что для ядерных реакторов код с исключениями использовать не стоит :)

www.joelonsoftware.com/articles/wrong.html

Exceptions are fine for quick-and-dirty code, for scripts, and for code that is neither mission critical nor life-sustaining. But if you’re writing an operating system, or a nuclear power plant, or the software to control a high speed circular saw used in open heart surgery, exceptions are extremely dangerous.

Немного сглаживая резкость высказываний — для прикладного некритичного ПО — пожалуйста, почему бы не использовать исключения. Для сложных приложений же, для которых стабильность работы — это «наше все» — лучше не надо, полный цикл написания/тестирования кода займет больше времени для доведения продукта до релиза + на выходе вероятнее всего будет менее стабильное (со скрытыми недостатками) ПО.

Я полностью поддерживаю данное мнение.
Joel довольно грамотный мужик, но иногда несёт такую ахинею, что слушать стыдно. По мне — это его отношение к исключениям направлено на то, чтобы показать, что он не такой как все.
полный цикл написания/тестирования кода займет больше времени для доведения продукта до релиза
по этому поводу, я могу сказать чушь и одно из оснований будет, то что Joel в своей практике очень мало использовал исключения, судя по его отношению к ним. Хочешь победить врага — знай его оружие. Он не знает…
на выходе вероятнее всего будет менее стабильное (со скрытыми недостатками) ПО
yeap, ключевое слово тут вероятнее и этим всё сказано :).
И еще — ваш единственный пример, где вы НЕ будете использовать исключения — слишком одинок и узок, таких случаев должно быть гораздо больше. Почему? Да просто не может быть только одного случая в рамках такой широкой проблемы, когда в программировании существует столько различных классов задач. По теории вероятности не может :)
Ну я ещё не «элитный» разработчик/архитектов/etc, получающий за свои знания многомиллионные прибыли :) Возможно со временем список и расширится. Пока что он такой ;).
Часто в Objective-C применяю исключения для обработки «редко возникающих ситуаций», когда парсер не смог обработать входной фрагмент, не удалось сформировать и отправить HTTP заголовок и прочее в таком же духе. До финального этапа обычно такие заглушки не доживают (заменяются на полноценную проверку всплывающих ошибок), но с помощью эксепшнов можно достаточно удобно на время «заткнуть» такие места в коде и все же получать какую-либо отладочную информацию если случится беда.
Вот тут есть хороший гайд про то когда надо, а когда нет бросать эксепшены.
download page

а статья сама по себе ничего не проясняет имхо. Так — показ мнений, и никакого обсуждения нужности\ненужности\вредности\etc.
OMG они раздают гайд в форме .exe файла! Боюсь предположить, что там внутри…
ПО мне так исключения в функциях/методах вызываться должны с возникновением только самых серьезных аномалий. Например, если надо обработать пришедшее письмо, а оно не отвечает стандарту. Или, скажем, ошибка деления на ноль, или проблема с выводом.

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

Для информативного вывода они не подходят совершенно, и для этого, ИМХО, не создавались.
Мне кажется вы пропустили (или не сформулировали) один имхо наиглавнейший плюс: exception хорошо подходит для методов, которые возвращают две и больше ошибок (проверка на допустимость аргументов и т.п.). Без них создаются а) странные «магические» результаты, которые б) приходится (!) постоянно проверять в if'е (эксепшн же необязательно, так как он и сам оборвет процесс).
У меня иногда мысли просто напросто «размазаны» :).
Я впринципе описывал аналогичную ситуацию на примере — когда один метод возвращает int, другой bool и в конечном итоге теряется любая информация.
+
Т.е. тем самым можно сократить неразбериху, создаваемую большим количеством возвращаемых кодов.


Мысль где-то рядом :).
Исключения должны использоваться для как это следует из названия, исключительных ситуаций, например в функцию приходит значение (например нулевой указатель), которое туда никак придти не должно, то есть DeveloperError (я это так предпоитаю называть, то есть программа просто кривая). В этом случае программа просто пишет что-нибудь в лог, выводит «developer error: blablabla» и дохнет.

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

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

А писать if после каждого вызова функции  —ад. Я лично в PHP буду стараться максимально использовать исключения, ибо руки отвалятся (я в курсе про сниппеты, но все же) писать вещи вроде:

if (!$database->query(«DO SOMETHING»))
{
trigger_error("...");
retrun false;
}

там где можно просто писать

$database->query(...);

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

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

Про выброс исключений и очистку ресурсов вы все правильно сказали, хотя посылка про неизвестность, критическая ошибка или нет, мне непонятна — про метод всегда известно, способен ли он сделать recover возникшей ошибки, или нет.
Собственно, сама возможность фильтровать по типу исключения внутри блока catch(SomeType ex) сделана для того, чтобы наглядно разделять recoverable и non-recoverable (извините за английский, он в данном случае выразительнее)
>>if после каждого вызова функции — ад

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

if(FAILED(hr = _SomeFunction())){
… handling error…
}

Ну и если вы посмотрите на исходники той же Windows (например, в Direct X, чтобы далеко не ходить), вы увидите, что они сами тоже не очень жалуют эксепшены, и в настоящее время продолжают писать в Cи/COM стиле. Так что рано еще хоронить коды возврата :)
Не стоит забывать, что в Microsoft есть определённый процент разработчиков индусов :).
Кстати, а вы бы в каких ситуациях использовали коды возрата?
Нет, я не про индусов :) я, в основном, про русских разработчиков в Той команде :)

Я бы использовал коды возврата в том случае, если это составляет логику работы программы. Ну и использовал бы их не в raw-формате, а как enum или его самописные аналоги (в Java)

P.S. Извините за медлительность, какой-то анонимус отметился в карму — видимо, не понравилось, что я слишком аргументированно спорил; и теперь ни писать в блог, ни комментить нормально не могу :( что с этим делать (плюсовать не надо, если вдруг, только ответьте)?
Как я уже неаписал выше — я тоже имел счастье в PHP проверять каждое обращение к БД — и мне это задолбало порядочно. я даже сниппет в редакторе сделал, который уже включает и if, и обработку ошибки, так что писать руками мне это не надо было  — но мне не нравится такой код, когда каждый вызов засунут в блок с if и trigger_error().

Отсутствие исключений — имхо — недостаток Си. Ну а при использовании directX, или любой другой Си-библиотеки можно или написать к ней обертку (в том числе с ексепшенами), удобную для себя — или же проверять эти вызовы вручную, если их немного.
Я бы не стал говорить про недостаток :) Иногда это превращается в достоинство — всегда известны тайминги операций (драйверы, low-level, nuclear facilities :)

Самая большая проблема исключений в том, что их генерация влечет за собой накладные расходы и операции, которые сами по себе могут быть источником проблем и исключений.
Простейший пример — нехватка памяти. Нужно выбросить exception, но не факт, что хватит памяти сконструировать сам экземпляр исключения. В управляемой среде (виртуальная машина java, интерпретатор php, или рантайм) сама среда берет на себя заботу об этом. В с++/MFC, например, чтобы памяти хватило, экземпляр исключения о нехватке памяти (и только такого) конструируется заранее, и затем везде выбрасывается один и тот же (вернее, указатель на один и тот же — чтобы исключить потенциально опасную операцию копирования объектов с контекста на контекст).

Насчет обертки — вы абсолютно правы, стоит делать как удобнее. Я только писал, что внутри DirectX продолжает оставаться COM-like, и не использует исключения — по указанным выше причинам.
Кстати СОМlike внутри остаётся ещё и потому что необходимо обеспечить совместимость с ранними версиями DirectX. А заново этот код под ООП никто переписывать уже не будет, т.к. затратно/невыгодна да и работать он, если разобраться, не будет…
Всмысле — переписывать с применением исключений :).
Накладные расходы — правда, но расходы идут именно прежде всего при выбрасывании исключения. А низкоуровневое программирование  — отдельный разговор, там свой подход — согласен, я прежде всего имел в виду десктопные или серверные приложения) А там код вида x = f1(f2(f3(y))); выглядит часто куда как аккуратнее, чем 3 ифа подряд)
Собстно, такой код, который вы привели, наглядно демонструирует, что при использовании исключений «мухи отдельно, коттлеты отдельно» — т.е. рабочий код чист и не загрязнен операциями зачистки/восстановления состояния после ошибок
> Исключения использовать нужно, но с умом!

Это и так очевидно, ради такого вывода статью писать смысла нет. :)

Кстати, в копилку минусов исключений примите ещё один: громоздкий код. Местами встречаются причудливые вложенные сочетания try/catch/finally. :)
Судя по всему, не всем очевидно, к сожалению :)
К сожалению вынужден не согласиться с Вашим итогом. Даже если производительность действительно важна, exceptions это не то, на чем можно серьезно сэкономить. Пострадает качество Вашего кода, а производительности вы получите крупицы. Хотите экономить, ищите более серьезные bottlenecks Вашего приложения, не надо заниматься дурью.
Исключения удобно использовать, когда надо быстро создать кусок кода и нет времени на описание всех возможных ветвлений алгоритма программы. Окружаем весь кусок кода try-catch блоком и пишем следующий. Этим экономим время, что бы успеть закончить разработку прототипа и показать заказчику. Таким образом на ранней стадии разработки уже получаем фидбэк. Затем, в период рефакторинга заменяем, по возможности, исключения.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации