Предисловие
Тема Исключений (за и против) не нова, и уже не раз обсуждалась. Но всё же, я надеюсь, что каждый из прочитавших данную статью почерпнёт что-то новое и полезное для себя.
Причиной появления этой публикации стало нежелание больше молчать и просто смотреть, как интернет заполняют «всезнающие» программисты, которые учат новичков в нашей сфере забивать гвозди микроскопом, находя десятки аргументов в защиту своих методов! Потому, эта публикация направлена, скорее, на новичка постигающего программирование и задающего вопросы. Она является моим «правильным ответом»
Итак, что же такое Исключение (Exception)?

Посмотрите в свой код. Можете ли вы к каждому исключению дописать «но ведь это невозможно» или «но это же исключено»? Думаю, мало кто сможет честно ответить «да». Если ваш ответ «нет» — значит часть исключений на самом деле не являются таковыми, просто вы использовали этот механизм, потому как вам показалось это более удобным. То самое «удобство» такого подхода будет рассмотрено далее.
Кто же должен определять, какие ситуации программа исключает, а какие нет?
Все исключения могут быть продиктованы только заданием или здравым смыслом, и ничем или никем иным. Исключение не определяется ни типом данных, ни их источником, хотя нередко можно услышать или прочитать в «умных» статьях: «Неправильный клиентский ввод не может быть исключением»… не верьте! Вот, просто, не надо в такое верить.
Вы можете в задании получить вполне разумное исключение неверного клиентского ввода: «С системой будут работать специально обученные менеджеры нашей компании, потому ввод неправильных данных исключён» или «Менеджер будет загружать в систему письма, которые уже прошли проверку правильности формата, поэтому формат всегда будет именно такой». Вот теперь заказчик сам вам сказал, где следует породить исключение в написанной для него программе (и ничего страшного, что это клиентский ввод). Разумеется, если речь всё же идёт о неком продукте, а не библиотеке, программу не надо просто ронять. Пускай на верхнем уровне висит обработчик исключений и превращает все необработанные исключения в ошибки, сохраняет данные и деликатно завершает выполнение (или передаёт управление основному модулю, если ошибка не в нём).
Но, как и обычно, не забываем читать между строк и уточнять задание. Если вас просят сохранить файл, уточните, возможна ли ситуация, что файл не сохранится. А если решили не уточнять, тогда не исключайте такую вероятность, а реализуйте реакцию на это событие. Ваш код не должен ни о чём умалчивать.
Или предусмотрите, или исключите.
Почему любое лишнее Исключение является вредным для кода?
Не раз сталкивался с ситуацией, когда отрицательный результат выполнения функции возвращали в виде исключения, хотя такой результат был предусмотрен самой задачей. На этот счёт слышал разные пояснения:
- Не передавать же по всей цепочке вызовов флаг завершения
- Мне надо передать данные, собранные до получения отрицательного ответа
- Функция может вернуть отрицательный результат по трём причинам. Так проще передать эту причину
- множество других доводов...
Почему же так не надо делать? Да потому, что:

- Вы не сможете смело использовать уже написанные методы в других местах, ведь они могут порождать неожиданные исключения;
- GOTO зло — потому что путает код, передавая управление в произвольную точку. Не следует думать, что передача управления, перепрыгивая произвольное количество вызовов в стеке, меньше путает ваш код, чем GOTO;
- Кому-то, а возможно и вам самим, потом надо будет что-то исправить или дописать в написанном коде. Не следует считать, что через 2 года вы влёт вспомните, что этот модуль системы для отрицательных ответов использует исключения. То есть, вам придётся вникать… и вникать не только в код, но и во все «необычности» подхода.
Не стал включать в список выше такие аргументы как «это правило хорошего тона» и «давайте всё использовать по назначению», итак написано уже достаточно.
Заключение
Старался не вдаваться лишние подробности и в каждое предложение вкладывать максимум смысла. Надеюсь у меня это получилось, и читая эти строки, вы думаете: «пять минут, а столько нового!» Ну что же, надеюсь это так.
Напоследок хотелось бы сказать, что не следует изворачиваться под давлением факторов, сроков и «так же проще», и писать неправильный код, зато быстро.
Совершенство и отказоустойчивость нашего кода и определяет наш профессионализм.
Комментарии (43)
pengyou
28.09.2016 14:05-2Бизнес определяет эволюцию языков. Часто получается так: бизнес-требования противоречат инженерным требованиям. Значит, с точки зрения инженера, языки и экосистемы развиваются по абсурдной траектории, инженер видит отрицательный отбор. Но бизнесу можно всё, что приводит к увеличению нормы прибыли, а значит, можно и исключения, и GOTO, и плевать на идеалы инженеров тоже можно. «MVP» и всё, сиди пиши говнокод молча, а то вспомним про hire & fire.
hdfan2
28.09.2016 14:22+5Исключение — это то, вероятность (возможность) чего исключается системой… это то что в условиях программы произойти не может.
Извините, но это чушь какая-то. Если это не может, то нет смысла и обрабатывать это. Может быть, лучше написать «произойти не должно»?
pehat
28.09.2016 14:28+5Вы не сможете смело использовать уже написанные методы в других местах, ведь они могут порождать неожиданные исключения
Fail fast? Не, не слышал. Лучше молча глотать и утаивать, что что-то пошло не так.
lair
28.09.2016 14:29+2Исключение — это то, вероятность (возможность) чего исключается системой… это то что в условиях программы произойти не может.
А откуда вы взяли это определение?
Все исключения могут быть продиктованы только заданием или здравым смыслом, и ничем или никем иным. Исключение не определяется ни типом данных, ни их источником
Вы так говорите, как будто тип и источник данных не определяются задачей.
Если вас просят сохранить файл, уточните, возможна ли ситуация, что файл не сохранится. А если решили не уточнять, тогда не исключайте такую вероятность, а реализуйте реакцию на это событие. Ваш код не должен ни о чём умалчивать.
Такая ситуация, очевидно, возможна. А вот теперь вопрос — зачем обрабатывать ее на каждом уровне кода (ведь "код не должен ни о чем умалчивать")?
Не раз сталкивался с ситуацией, когда отрицательный результат выполнения функции возвращали в виде исключения, хотя такой результат был предусмотрен самой задачей
Что такое "отрицательный результат выполнения функции"?
Почему любое лишнее Исключение является вредным для кода?
Как определить, является ли исключение лишним?
NeoCode
28.09.2016 14:38Исключения это интересная тема. Если где-то в недрах кода (возможно даже в сторонней библиотеке) возникла недопустимая ситуация — например невозможность выделить память — то нужно предпринять какие-то действия. По идее, это может быть и код ошибки, и исключение, и даже аварийное завершение работы всей программы. Но что именно?
В какой-то момент мне пришла в голову мысль, что в языке программирования должна существовать некоторая конструкция, определяющая «ошибочную ситуацию». Нечто среднее между «return кода_ошибки» и «throw исключения». То есть библиотека говорит «у меня произошла ошибка», а как именно она должна быть обработана — это вопрос вызывающего кода. Ведь даже обработка исключений может быть разной (SEH, DWARF, SJLJ). В конце концов, код возврата — это тоже способ организации исключений, особенно если компилятор возьмет на себя часть этой работы (очевидно что для этого потребуется сказать компилятору какие коды означают ошибки и обеспечить тип возврата всех функций, участвующих в этой системе).
То что любая функция может внезапно выкинуть любое исключение (как в С++) — это плохо и по сути является аналогом goto. Реализация в Java (с явным указанием исключений которые могут быть выброшены) лучше (именно тем что там исключения указываются явно). Но можно пойти еще дальше.
В некотором роде исключения — это модуль языковой функциональности (как RTTI в C++, отключаемую опцией компиляции). В определенных случаях (например программирование под микроконтроллеры с малым объемом памяти) исключения целесообразно отключать вообще, переводя весь код на самую простую реализацию — кодами возврата. При этом хотелось бы, чтобы библиотеки были общие (т.е. не держать отдельные наборы библиотек для каждой реализации исключений).MacIn
28.09.2016 16:08То что любая функция может внезапно выкинуть любое исключение
Почему бы не ловить все исключения?
Lure_of_Chaos
28.09.2016 16:34Реализация в Java (с явным указанием исключений которые могут быть выброшены) лучше (именно тем что там исключения указываются явно).
Не все с этим согласны
Antervis
29.09.2016 06:02В какой-то момент мне пришла в голову мысль, что в языке программирования должна существовать некоторая конструкция, определяющая «ошибочную ситуацию». Нечто среднее между «return кода_ошибки» и «throw исключения».
в с++ есть std::error_code.
impwx
28.09.2016 14:46+2«То, чего никогда не может быть» — это только необработанное исключение. Было бы странно вводить в большинство современных языков довольно сложный механизм
try\catch\throw
для случаев, которые вообще никогда не должны выполняться, не находите?
В более широком смысле исключение описывает ситуацию, в результате которой локальный кусок кода не может дальше выполняться. В таком случае оно вполне логично «всплывает» до того уровня, где может быть осмысленно обработано. Это позволяет разделять ответственность, структурирует код и отлично сочетается со стековой архитектурой.
В статье ни одного аргументированного довода против исключений не нашел. Всё сводится к тому, что это «сложно» или «не нравится». Сложность вижу только в том случае, если нет порядка и половина функций возвращает значения-ошибки, а половина кидает исключения. Если принять за правило, что все функции работают унифицированно — не запутаешься, и через два года не нужно будет ничего вспоминать.
А дальше вообще начинаются «Вредные советы»:
Пускай на верхнем уровне висит обработчик исключений и превращает все необработанные исключения в ошибки, сохраняет данные и деликатно завершает выполнение
Когда исключение всплывает, любой уровень программы может узнать об этом и при необходимости пробросить его дальше. Вы же предлагаете ловить исключение на самом верхнем уровне, а дальше что — оповещать оттуда все необходимые компоненты? Это вывернет зависимости наизнанку, связность компонентов вырастет, а код станет неподдерживаемым.
Вы не сможете смело использовать уже написанные методы в других местах, ведь они могут порождать неожиданные исключения;
Если вы вернете из функции неизвестный код ошибки, ситуация будет еще опаснее. В лучшем случае вы всё равно получите исключение, только не осмысленное, а что-то типа «обращение к нулевому указателю» или «выход за пределы массива» при работе с некорректными данными. В худшем — ошибка будет проглочена и программа молча выполнит неожиданный код, вероятно повреждая при этом данные.
Возможно, автор не до конца разобрался с механизмом исключений, или сознательно решил этого не делать из этических соображений?MacIn
28.09.2016 16:09В худшем — ошибка будет проглочена и программа молча выполнит неожиданный код, вероятно повреждая при этом данные.
С исключениями тоже так может быть — пустой catch/except блок.
kahi4
28.09.2016 14:55У исключений есть большое преимущество перед возвратом функции. Просто огромнейшее: стектрейс. Неожиданно вывалившееся исключение можно проверить, отдебажить, воспроизвести. Если функции начинают возвращать -1 — найти источник ошибки гораздо сложнее.
А еще бывает так, что памяти нет ну совсем. Исключение пролетит через всю систему до того уровня, когда уже можно принимать решение о том, что делать дальше. Возврат кода ошибки же либо наплодит во всем трейсе лишние условия проверки, либо же попытается выполнять код дальше, вновь выделить память и зависнет намертво.
Исключения — сильный механизм и его нужно применять с умом. К сожалению, помимо того, что он сильный, он еще и требовательный по ресурсам (добавляет много оверхеда), поэтому нужно понимать, когда нужно именно бросать исключение, а стоит сделать возврат из функции.
VioletGiraffe
28.09.2016 15:05+2ИМХО главная проблема исключений — нечитаемость кода. Очень сложно найти место, где исключение будет обработано. А ещё бывает, что где-то забыли catch, или написали там не тот конкретный тип исключения. И всё, вроде, работает, и даже сообщение об ошибке выдаётся, но ошибка обрабатывается не так, как было задумано. ИМХО программировать с использованием кодов возврата проще. Как минимум, до какого-то уровня сложности системы.
vlreshet
28.09.2016 15:31Не могу сказать про ситуацию в целом, но, допустим, в PHP — если всё делать «по фен-шую» то код должен бросать не стандартное исключение, а свой собственный класс исключения, который наследуется от встроенного. И потом не сложно найти где ловится именно наш тип исключения, а не исключение впринципе. Как-то так.
VioletGiraffe
28.09.2016 15:54+1В Java и С++ не запрещено ловить базовый тип, даже если бросается наследник (что логично). Скажем так: можно сделать нормально, но никто не мешает сделать коряво (что, впрочем, вряд ли является отличительной чертой исключений).
lair
28.09.2016 18:04+2ИМХО программировать с использованием кодов возврата проще.
Вот только проигнорировать код возврата (во многих языках) проще, чем исключение.
Antervis
29.09.2016 06:17исключения как инструмент совершенно не уникальны в том, что при корявом их применении код становится сложным. Например, как только начинаешь использовать коды возврата, все функции по умолчанию начинают возвращать не bool/string/..., а код ошибки. И в конечном итоге оказывается, что при возникновении какой-то ошибки её код возврата тянется через всю программу, а обрабатываются они точно так же в ограниченном количестве мест. Архитектура получается точно такая же, как и с исключениями, но с исключениями проще писать как позитивный, так и негативный сценарий выполнения.
Плюс, исключния более приятны когда пытаешься разбить большие функции
MacIn
28.09.2016 16:10+1У исключений есть большое преимущество перед возвратом функции. Просто огромнейшее: стектрейс.
Это если оно unhandled и на самом деле исключение.
vyatsek
28.09.2016 16:01Извините чукча не читатель. Плохой учитель губит хороших учеников.
«Все исключения могут быть продиктованы только заданием или здравым смыслом», о боже откуда это? А как же формализация?
Исключения должны выбрасываться в том случае, если нарушаются одно из трех условий при вызове члена типа.
Предусловие, инвариант, пост условие. Как это разумно и правильно применить в контекте проекта это уже другой вопрос.
Предусловие — проверяет входные параметры и инвариант типа. Потом происходит выполнение каких-то операций, которые могут нарушать инвариант. Перед возвращением значения происходит проверка постусловий и инварианта.
Это если в кратце.vyatsek
28.09.2016 16:29Не успел отредактировать.
Предусловия это условия при которых метод не сможет выполнить возложенную на него обязанность, обычно в предусловиях проверяют валидность входных данных.
Пост условия это проверка условий, что метод выполнил корректно свою обязанность. Инвариант это условия которые должны выполняться всегда, исключение составляют методы в которых этот инвариант на время выполнения может быть нарушен.
Например есть тип Employee, c методами IncreaseBonus и DecreaseBonus.
Пусть будет объект employee с с бонусом равным 10. И кто-то например вызывает employee.DecreaseBonus(20), методы не имеют возвращаемого значения. Предусловие проверяет что 20 > 0, инваринат проверяет что текущее значение бонуса больше 0, 10>0.
Потом происходит вычисление и бонус становится -10. Проверки на пост условие нет, хотя теоретически это может быть успешность записи еще куда либо, а инвариант проверят что бонус отрицательный и выбрасывает исключение. И объект находится в неконсистетном состоянии, при вызове любого другого метода инвариант должен выбрасывать исключение.
Данный пример с точки зрения дизайна не является лучшим, но наглядно демонстрирует условия.
В реальности примером инварианта в C# является правильная реализация интерфейса IDisposable, где перед каждым методом проверяет флаг isDisposed, другим примером может быть проверка isConnected при вызове в типах которые оперируют связью. Примеры предусловий это проверка аргументов на валидность значений.
По поводу проверки и бросания исключений от пользовательского ввода, тут все определяется контрактом. Если модель не может работать с пустой строкой, то если значение передаваемого параметра пустая строка — исключение однозначно, чтобы исключения не возникало, об этом должен позаботиться UI — не давать применить такое значение.
Вы также не затронули тему о иерархии исключений и их обработке, но этого вообще хватит на отдельный пост.
Учите мат часть она давно уже написана.
MacIn
28.09.2016 16:03+3Вы не сможете смело использовать уже написанные методы в других местах, ведь они могут порождать неожиданные исключения;
А что такое «неожиданное исключение» и почему оно является препятствием? По сути, это неожиданный код возврата. Функция возвращает вам, скажем, длину буфера, или -1 в случае неудачи. А вы не знали, что значение может быть отрицательным — это неожиданный для вас результат. Значит ли это, что код возврата нельзя использовать? Нет. С исключениями то же самое — выбрасываемые в виде кода ошибки исключения должны быть документированы, так же как и возвращаемые функцией значения.
GOTO зло — потому что путает код, передавая управление в произвольную точку. Не следует думать, что передача управления, перепрыгивая произвольное количество вызовов в стеке, меньше путает ваш код, чем GOTO;
Ничего подобного. Если так рассуждать, то мы должны отказаться от конструкций:
for ()...{
break;
}
if (){
…
} else {
…
}
В первом случае у нас есть неявный GOTO вовне цикла, во втором — неявный GOTO к блоку ELSE.
GOTO — не must die. Must die неправильное его использование. Самая большая проблема с goto — это прыжок назад по коду с созданием петли. Именно это тяжело отслежить и понять, именно из-за этого получается пресловутое спагетти. Исключение не бросает нас вверх по ходу исполнения, оно бросает нас вниз, дальше.
Не следует считать, что через 2 года вы влёт вспомните, что этот модуль системы для отрицательных ответов использует исключения
Такой же странный аргумент, как и первый. И тот же самый контр-аргумент. Вот вы надеетесь на то, что код ошибки — это -1. А потом добавили еще -2 и -3. Через поименованные константы, разумеется. А результат функции по-прежнему проверяете на == -1. И? Какая разница? Кто мешает вам ловить все коды ошибки меньше нуля или все исключения (определенные + «остальное»)?
Использовать нужно то, что сделает ваш код читаемым и надежным. Лучше коды ошибок? Пожалуйста. Лучше исключения? На здоровье. Лучше goto с переходом в блок деинициализации в конце функции? Да рали бога.
kroshanin
28.09.2016 16:27+1В разработке руководствуюсь правилом: «исключения для программистов, а не для пользователей.»
То есть если пользователь забыл ввести значение в поле формы — это просто ошибка, не исключение.
А вот если где-то «внутри» очень важная переменная вдруг оказалась не заданной — нужно кидать исключение, причем вывести и имя функции, и сообщение, и значения других параметров, которые помогут найти эту ошибку.
G-M-A-X
28.09.2016 17:20>GOTO зло — потому что путает код, передавая управление в произвольную точку.
В PHP не в произвольную, есть разумные ограничения.
>Вот теперь заказчик сам вам сказал, где следует породить исключение в написанной для него программе
Не в этих ли случаях их использовали, давая указанные вами пояснения? :)
eXTreMeHawk
29.09.2016 12:12Удивительно, но в статье ничего не сказано о том, что исключения ломают referential transparency. И это тот самый пункт номер 1 с которого надо начинать, когда мы говорим вообще что-либо об исключениях. А ещё они также не composable + не работают в multi-threaded окружении.
lair
29.09.2016 14:25Referential transparency — это хорошая такая штука, особенно в функциональном программировании, но вот только не всегда достижимая. Один раз у вас память выделилась, другой раз — нет.
А ещё они [...] не работают в multi-threaded окружении.
Работают. Просто надо уметь их готовить.
eXTreMeHawk
01.10.2016 08:56А есть подходы, которые не надо уметь как-то специально готовить и которые просто работают, при этом всегда и корректно… А в моменты когда они не работают корректно, программа просто не компилируется ;-)
lair
01.10.2016 12:43Что же это за волшебные подходы?
eXTreMeHawk
02.10.2016 07:52Вот здесь, если я правильно помню, было довольно хорошо про это рассказано: Railway Oriented Programming
lair
02.10.2016 11:18Вместо ссылки на часовое видео, можно было просто сказать "монада
Try
". Так вот, у меня для вас плохие новости.
(а) монада
Try
не решает проблему referential transparency. Если внутри функции, пусть даже она возвращаетTry[T]
, есть побочный эффект (например, работа с бд), функция не будет чистой, и, как следствие, referential transparency будет нарушена. Да фиг с ней, с БД, банальное выделение памяти — и ваша функция уже недетерминирована.
(б) монада
Try
не решает проблему обработки ошибок в многопоточности: если вы положите функцию, возвращающуюTry[T]
, в другой поток, и проигнорируете ее результат — как вы и делаете в другом комментарии, — вы ничего не узнаете о случившихся ошибках.
(ц) в обоих этих случаях компилятор вам никак не поможет. Более того, прямо скажем, есть еще сильно больше одного способа "сломать"
Try
(впрочем, как и любой case class) даже при полной поддержке компилятором — и это еще не упоминая того факта, что описанная вами поддержка есть далеко не везде (скажем, в F# на необработанный кейс будет предупреждение, но код скомпилируется, в Scala, афаик, так же).
G-M-A-X
29.09.2016 14:30>не работают в multi-threaded окружении
1. PHP, Node.JS — однопоточные. :) Нам можно :)
2. А если войти в критическую секцию, то, кмк, все должно работать. Но сложновато. Как и любой другой многопоточный код. :)
MacIn
29.09.2016 17:05не работают в multi-threaded окружении.
Это с какой стати? Вас не затруднит пояснить развернуто? Без каких-либо проблем используем исключения в многопоточных системах.eXTreMeHawk
01.10.2016 08:51try { Task(some_work).run() // (1) catch { // (2) never reach this point }
В примере выше, если Task запускает some_work в другом треде и в этом треде some_work породит исключение мы по дефолту в точке (2) его не поймаем никогда, если только не напишем специальную обвязку вручную, для проброса исключений из слейв-треда в мастер-тред.
lair
01.10.2016 12:46Ну так вы же проигнорировали результат
Task.Run
— так что неудивительно, что вы не получили информации о ходе выполнения. В таком коде, прямо скажем,some_work
может никогда и не выполниться.eXTreMeHawk
02.10.2016 07:47Это просто схемотичный пример, а не кусок кода, который должен компилироваться. В интернете погуглите пожулуйста «Referential transparency» и найдёте много информации почему исключения её ломают и, самое главное, как этого можно избежать с примерами кода и т. п.
lair
02.10.2016 11:08Я знаю, почему исключения ломают referential transparency, но мы-то здесь не о referential transparency, а о многопоточности.
Так вот, в вашем коде полностью проигнорирован результат
some_work
— поэтому никакая обработка ошибок, включая монадуTry
, про которую вы пишете рядом, вам не поможет. Более того, как я уже писал, поскольку результат проигнорирован, ваш код может завершиться раньше, чемsome_work
начнется. Ну да, такая вот многопоточность, только конкретно исключения тут ни при чем.eXTreMeHawk
02.10.2016 11:35Я имел ввиду следующее. Сейчас попробую расписать подробнее. Допустим у вас есть поток B в котором происходит какая-то полезная работа. В какой-то момент в этом потоке B происходит ошибка и выбрасывается исключение. Это исключение может быть перехвачено и обработано только внутри потока B. Как поток A, который расчитывает, что от потока B рано или поздно придёт какой-то результат, узнает, что в B вычисление завершилось неудачей? По умолчанию никак. Но можно написать обвязку, которая будет прокидывать ошибку из потока B в поток A (тем или иным способом) и уже дальше в потоке А, например, кидать исключение. Это будет работать, но для этого придётся написать какой-то код. Ещё раз, исключение брошенное в одном потоке можно поймать и обработать только из этого же потока. По умолчанию другие треды про него ничего не узнают, если не предпринять специальных телодвижений.
lair
02.10.2016 11:37Как поток A, который расчитывает, что от потока B рано или поздно придёт какой-то результат, узнает, что в B вычисление завершилось неудачей?
Давайте начнем с простого вопроса: как поток A узнает, что от потока B пришел какой-то результат? По умолчанию это так не работает.
(вау, я только что нашел фундаментальную проблему в операторе
return
)
MacIn
02.10.2016 17:03Как поток A, который расчитывает, что от потока B рано или поздно придёт какой-то результат, узнает, что в B вычисление завершилось неудачей? По умолчанию никак
Воу-воу-воу, секундочку. Если мы ожидаем результата от потока Б, то мы ожидаем какого-то события, сигнализирующего достижения результата, или окончания потока Б. Т.е. в любом случае у нас будет код, который является прослойкой между двумя этими потоками. Так или иначе. Кто мешает этой прослойке проверять исключения? Например, что-то вроде
WaitForSingleObject(hThreadBEvent) if lThreadB.Outcome == oFailure CheckException(lThreadB).... ... ... Thread.HandleException(Exception){ Terminate; Outcome = oFailure; SetEvent(hmyEvent) }
lair
02.10.2016 20:05Прямо скажем, .net-овский
Task
, который местная реализация монадыFuture
, как-то так и делает (не по реализации, а по результирующему поведению):
var task = Task.Run(somework); //... await task; // завершится только тогда, когда somework закончен, и если в somework был эксепшн, он будет выкинут здесь
MacIn
01.10.2016 14:12+1Так, простите, где здесь пример того, что исключения не работают в многопоточном окружении?
Если исключение будет порождено методом run, оно поймается. Исключения, порождаемые some_work'ом, должны ловиться исключением обертки Task, запускающей отдельный поток.
Antervis
03.10.2016 06:42функция, которая может то выполниться, то зафейлиться, в принципе не может быть чистой. Просто при использовании исключений она выглядит чистой, а ошибки и результат выполнения позитивного сценария обрабатываются в разных местах
vlreshet
А я думаю «пять минут потраченные впустую», потому что в статье нет ни одного конктетного совета, а есть только общий и весьма очевидный посыл — «исключения это не серебряная пуля, использовать их или нет надо смотреть по ситуации».
MacIn
Да ну? По-моему посыл как раз использовать исключения только для нештатных ситуаций, а не «смотреть по ситуации».