Страницы

Поиск по вопросам

четверг, 4 октября 2018 г.

Как правильно использовать исключения

Преимущественно всегда думал, что бывает не лишним на каждый тип исключения выводить соответствующее сообщение об ошибке. Речь идет о ситуациях, когда ничего кроме сообщения в блоке catch делать не зачем, т.е. можно было бы просто использовать общий вариант:
catch (Exception ex) { // <сообщение> }
а не
catch (DivideByZeroException) { // <сообщение про одно> } catch (FormatException) { // <сообщение про другое> } catch (ArithmeticException) { // <сообщение про третье> } catch (Exception ex) { // <сообщение> }
Но как-то несколько раз попадались на глаза утверждения типа "когда нет особо критичных целей, то отлавливать много исключений без нужды это плохой тон, безосновательное занятие и все в этом духе". Вроде как это "антипаттерн". Пользователю не важно, что там за ошибка, главное вывести сообщение, что, грубо говоря, функция не выполнилась, а по какой причине - его не касается.
В статьях с противоположным мнением наоборот утверждали, что пользователь должен знать, что случилось, по какой причине что-то пошло не так.
Так как поступать с исключениями в таких ситуациях? Определять "на глаз" в каком месте обязательно нужно уведомлять о возможных причинах ошибки, а в каком достаточно общего сообщения? Или есть какие-то уже сформулированные критерии по этому поводу? Или по сути вообще может без разницы, и все эти рассуждения не имеют значения?


Ответ

Вопрос конечно очень холиварный =) но тем не менее, поделюсь своими представлениями, ни в коей мере не претендуя на абсолютную истину.
Любая программа, работающая в реальных условиях и окружении с участием пользователя или без, способна генерировать массу исключений по разным причинам. Исключение составляют учебно-олимпиадные программы, которые работают в "идеальных" условиях, т.е. входные данные жестко регламентированы и ошибка пользователя исключена условиями задачи.
У каждого исключения может быть несколько причин для появления:
Ошибка пользователя при вводе данных тем или иным способом. Исключения возникшие по этой причине ловить необходимо, чтобы сообщить пользователю о его ошибке и дать возможность повторить ввод данных или некоторый набор действий для продолжения работы программы. Ошибка возникшая по вине среды окружения, например операционной системы или другой программы или библиотеки с которой вам приходится взаимодействовать. Такие исключения, в среднем, ловить противопоказано, т.к. единственное что можно сделать в таком случае, это попытаться корректно завершить работу, однако даже это может привести к непредсказуемым последствиям и порче данных пользователя, что вряд ли обрадует последнего. Однако, если вы уверены что ошибка, вызвавшая исключение, безвредна для данных или само исключение несет сугубо информативный характер, как, например, исключения при попытке установить сетевое соединение или при работе с файлами, то такое исключение может быть поймано и обработано. Ошибка возникшая по вине самой программы или ее части, например "любимый" всеми NullReferenceException. Исключения подобного рода необходимы на этапе отладки. Ловить их в коде никакого смысла нет, т.к. в процессе отладки, в идеале, все места кода, где могут возникнуть исключения по вине программы, должны быть исправлены. Как временная мера, можно и поймать, но тут есть большой риск что эта временная мера так и останется навсегда костылем в коде.
В целом, исключение генерируется тогда, когда исполняемый код не знает что делать в возникшей ошибкой.
Я для себя вывел 3 простых правила по обработке исключений:
Если можно исправить код так, чтобы исключение не возникало - исправляем код. Если не знаешь что делать с ошибкой которая стала причиной исключения, не лови его и дай программе упасть. Если уверен что знаешь что делать с ошибкой, ловим, заносим в логи, исправляем ошибку и бежим дальше либо падаем, тут уж по обстоятельствам.

Комментариев нет:

Отправить комментарий