Для чего нужна обработка исключений
Что такое исключения в программировании
Рассказ об ошибках, которые можно предусмотреть заранее.
Большинство наших проектов устроены так: когда во время работы программы возникает какая-то ошибка, то программа аварийно завершается. Иногда при этом она выдаёт сообщение об ошибке. Кажется, что это нормальная ситуация, но на самом деле большинство ошибок можно предусмотреть и научить программу правильно с ними работать. Для этого нам нужны обработчики ошибок.
Что такое обработчик ошибок
Чтобы программа знала, что делать, если возникла какая-то ошибка, используют обработчики исключительных ситуаций, или, проще говоря, обработчики исключений. Смысл такой:
Такие обработчики есть не в каждом языке программирования, но большинство современных языков это умеют делать.
Пример программы без обработчика исключений
Допустим, у нас в программе на Python предусмотрено чтение данных из файла и есть такой код:
Но если на диске этого файла не будет, то компьютер, когда дойдёт до этой строчки, выдаст ошибку:
Давайте нарисуем это в виде простой схемы:
Получается, что наша задача — предусмотреть вариант, что на диске не будет нужного файла, и придумать поведение программы в этом случае. Используем для этого обработчик исключений.
Программа с обработчиком исключений
Если мы знаем, что в каком-то месте возможна ошибка, то можем тогда предусмотреть этот сценарий и подстраховаться. Для этого используют обработчик и делают так:
В этой ситуации программа не зависнет и не вывалится с ошибкой, а сама сможет её обработать и делать дальше то, что нужно:
Команда try — это начало нашего обработчика исключений. Она говорит компьютеру: «Попробуй выполнить вот эту команду, а мы посмотрим, что произойдёт».
Except — это какую ошибку мы ожидаем здесь увидеть. В нашем случае мы хотим предусмотреть случай, что такого файла нет, поэтому пишем стандартную ошибку для такой ситуации.
👉 Сравните текст этой ошибки с тем, что нам выдал компьютер в предыдущем разделе.
В других языках конструкция обработчика исключений может выглядеть по-другому, но смысл тот же: говорим компьютеру, какую команду нужно выполнить и что делать, если появилась конкретная ошибка.
Когда что-то не предусмотрено — будет ошибка
Если программе в этом блоке встретится другая ошибка, не та, которую мы предусмотрели, то программа остановится и всё перестанет работать. Например, вот какие ошибки могут возникнуть с файлом:
Во всех этих случаях программа сломается, потому что мы не предусмотрели эти ситуации:
Получается, всё нужно делать с обработкой исключений?
Конечно, есть места в коде, которые лучше делать с обработкой ошибок: работа с файлами, сетевые запросы или получение внешних данных. Но запихивать исключения на каждую команду в программе точно не стоит.
Исключения
Исключение — это любое состояние ошибки или непредвиденное поведение, возникающее при выполнении программы. Исключения могут возникать из-за сбоя в вашем или вызываемом коде (например, в общей библиотеке), недоступности ресурсов ОС, неожиданных состояний, возникающих в среде выполнения (например, код, который невозможно проверить) и по другим причинам. После некоторых из этих состояний приложение может восстановиться, после других — нет. В большинстве случаев вы можете выполнить восстановление после большинства исключений в приложении, но не после исключений среды выполнения.
Исключения и традиционные методы обработки ошибок
Не требует определенного синтаксиса языка для обработки исключений, а позволяет каждому языку определить собственный синтаксис.
Исключения можно создавать между разными процессами и даже компьютерами.
В приложение можно добавить код обработки исключений для повышения надежности программы.
Исключения обеспечивают ряд преимуществ по сравнению с другими методами уведомления об ошибках, например кодами возврата. Сбои не остаются незамеченными, так как среда выполнения завершает работу приложения при наличии необработанного исключения. Недопустимые значения не распространяются по системе из-за того, что код не способен выполнить проверку кода возврата ошибки.
Часто встречающиеся исключения
В следующей таблице перечислены некоторые общие исключения с примерами возможных причин.
Обработка ошибок и исключения
Содержание
Методы обработки ошибок [ править ]
2. Коды возврата. Основная идея — в случае ошибки возвращать специальное значение, которое не может быть корректным. Например, если в методе есть операция деления, то придется проверять делитель на равенство нулю. Также проверим корректность аргументов a и b :
При вызове метода необходимо проверить возвращаемое значение:
Минусом такого подхода является необходимость проверки возвращаемого значения каждый раз при вызове метода. Кроме того, не всегда возможно определить тип ошибки.
3.Использовать флаг ошибки: при возникновении ошибки устанавливать флаг в соответствующее значение:
Минусы такого подхода аналогичны минусам использования кодов возврата.
4.Можно вызвать метод обработки ошибки и возвращать то, что вернет этот метод.
Но в таком случае не всегда возможно проверить корректность результата вызова основного метода.
5.В случае ошибки просто закрыть программу.
Это приведет к потере данных, также невозможно понять, в каком месте возникла ошибка.
Исключения [ править ]
В Java возможна обработка ошибок с помощью исключений:
Каждый раз, когда при выполнении программы происходит ошибка, создается объект-исключение, содержащий информацию об ошибке, включая её тип и состояние программы на момент возникновения ошибки. После создания исключения среда выполнения пытается найти в стеке вызовов метод, который содержит код, обрабатывающий это исключение. Поиск начинается с метода, в котором произошла ошибка, и проходит через стек в обратном порядке вызова методов. Если не было найдено ни одного подходящего обработчика, выполнение программы завершается.
Таким образом, механизм обработки исключений содержит следующие операции:
Классификация исключений [ править ]
Проверяемые исключения [ править ]
Наследники класса Exception (кроме наслеников RuntimeException ) являются проверяемыми исключениями(checked exception). Как правило, это ошибки, возникшие по вине внешних обстоятельств или пользователя приложения – неправильно указали имя файла, например. Эти исключения должны обрабатываться в ходе работы программы, поэтому компилятор проверяет наличие обработчика или явного описания тех типов исключений, которые могут быть сгенерированы некоторым методом.
Все исключения, кроме классов Error и RuntimeException и их наследников, являются проверяемыми.
Error [ править ]
Класс Error и его подклассы предназначены для системных ошибок. Свои собственные классы-наследники для Error писать (за очень редкими исключениями) не нужно. Как правило, это действительно фатальные ошибки, пытаться обработать которые довольно бессмысленно (например OutOfMemoryError ).
RuntimeException [ править ]
Обработка исключений [ править ]
Как и было сказано раньше, определение метода должно содержать список всех проверяемых исключений, которые метод может бросить. Также можно написать более общий класс, среди наследников которого есть эти исключения.
try-catch-finally [ править ]
Сразу после блока проверки следуют обработчики исключений, которые объявляются ключевым словом catch.
Обработка исключений, вызвавших завершение потока [ править ]
Информация об исключениях [ править ]
Разработка исключений [ править ]
Исключения в Java7 [ править ]
Можно объявлять несколько ресурсов, разделяя их точкой с запятой:
Компилятор Java SE 7 тщательнее анализирует перебрасываемые исключения. Рассмотрим следующий пример:
Примеры исключений [ править ]
Гарантии безопасности [ править ]
При возникновении исключительной ситуации, состояния объектов и программы могут удовлетворять некоторым условиям, которые определяются различными типами гарантий безопасности:
Если будет брошено исключение в этом классе, то тогда гарантируется, что ивариант «левая граница интервала меньше правой» сохранится, но значения left и right могли измениться.
Когда нужны исключения
Предисловие
Тема Исключений (за и против) не нова, и уже не раз обсуждалась. Но всё же, я надеюсь, что каждый из прочитавших данную статью почерпнёт что-то новое и полезное для себя.
Причиной появления этой публикации стало нежелание больше молчать и просто смотреть, как интернет заполняют «всезнающие» программисты, которые учат новичков в нашей сфере забивать гвозди микроскопом, находя десятки аргументов в защиту своих методов! Потому, эта публикация направлена, скорее, на новичка постигающего программирование и задающего вопросы. Она является моим «правильным ответом»
Итак, что же такое Исключение (Exception)?
Исключение — это то, вероятность (возможность) чего исключается системой… это то что в условиях программы произойти не может.
Посмотрите в свой код. Можете ли вы к каждому исключению дописать «но ведь это невозможно» или «но это же исключено»? Думаю, мало кто сможет честно ответить «да». Если ваш ответ «нет» — значит часть исключений на самом деле не являются таковыми, просто вы использовали этот механизм, потому как вам показалось это более удобным. То самое «удобство» такого подхода будет рассмотрено далее.
Кто же должен определять, какие ситуации программа исключает, а какие нет?
Все исключения могут быть продиктованы только заданием или здравым смыслом, и ничем или никем иным. Исключение не определяется ни типом данных, ни их источником, хотя нередко можно услышать или прочитать в «умных» статьях: «Неправильный клиентский ввод не может быть исключением»… не верьте! Вот, просто, не надо в такое верить.
Вы можете в задании получить вполне разумное исключение неверного клиентского ввода: «С системой будут работать специально обученные менеджеры нашей компании, потому ввод неправильных данных исключён» или «Менеджер будет загружать в систему письма, которые уже прошли проверку правильности формата, поэтому формат всегда будет именно такой». Вот теперь заказчик сам вам сказал, где следует породить исключение в написанной для него программе (и ничего страшного, что это клиентский ввод). Разумеется, если речь всё же идёт о неком продукте, а не библиотеке, программу не надо просто ронять. Пускай на верхнем уровне висит обработчик исключений и превращает все необработанные исключения в ошибки, сохраняет данные и деликатно завершает выполнение (или передаёт управление основному модулю, если ошибка не в нём).
Но, как и обычно, не забываем читать между строк и уточнять задание. Если вас просят сохранить файл, уточните, возможна ли ситуация, что файл не сохранится. А если решили не уточнять, тогда не исключайте такую вероятность, а реализуйте реакцию на это событие. Ваш код не должен ни о чём умалчивать.
Или предусмотрите, или исключите.
Почему любое лишнее Исключение является вредным для кода?
Не раз сталкивался с ситуацией, когда отрицательный результат выполнения функции возвращали в виде исключения, хотя такой результат был предусмотрен самой задачей. На этот счёт слышал разные пояснения:
Заключение
Старался не вдаваться лишние подробности и в каждое предложение вкладывать максимум смысла. Надеюсь у меня это получилось, и читая эти строки, вы думаете: «пять минут, а столько нового!» Ну что же, надеюсь это так.
Напоследок хотелось бы сказать, что не следует изворачиваться под давлением факторов, сроков и «так же проще», и писать неправильный код, зато быстро.
Совершенство и отказоустойчивость нашего кода и определяет наш профессионализм.
Обработка исключений
При выполнении программы может возникнуть ряд ненормальных условий и ошибок, называемых исключениями. К ним могут относиться нехватки памяти, ошибки выделения ресурсов и невозможность поиска файлов.
Библиотека Microsoft Foundation Class использует схему обработки исключений, которая моделируется в тесном соответствии с предложенным Комитетом по стандартам ANSI для C++. Перед вызовом функции, которая может столкнуться с аномальной ситуацией, необходимо настроить обработчик исключений. Если функция обнаруживает аномальное состояние, она вызывает исключение, и управление передается обработчику исключений.
Несколько макросов, входящих в библиотека Microsoft Foundation Class, настроили обработчики исключений. Ряд других глобальных функций помогает создавать специализированные исключения и завершать программы при необходимости. Эти макросы и глобальные функции делятся на следующие категории:
Макросы исключений, которые представляют собой структуру обработчика исключений.
Функции, создающие исключения), которые создают исключения конкретных типов.
Функции завершения, которые вызывают завершение программы.
Примеры и дополнительные сведения см. в статье исключения.
Макросы исключений
Функции Exception-Throwing
Имя | Описание |
---|---|
AfxThrowArchiveException | Создает исключение архива. |
AfxThrowFileException | Вызывает исключение файла. |
AfxThrowInvalidArgException | Вызывает исключение недопустимого аргумента. |
AfxThrowMemoryException | Вызывает исключение памяти. |
AfxThrowNotSupportedException | Вызывает исключение «не поддерживается». |
AfxThrowResourceException | вызывает исключение Windows ресурс — не найдено. |
AfxThrowUserException | Создает исключение в действии, инициированном пользователем. |
MFC предоставляет две функции генерации исключений, специально предназначенные для исключений OLE:
Функции исключений OLE
Имя | Описание |
---|---|
AfxThrowOleDispatchException | Создает исключение в функции OLE Automation. |
AfxThrowOleException | Вызывает исключение OLE. |
Для поддержки исключений баз данных классы баз данных предоставляют два класса исключений, CDBException и и CDaoException глобальные функции для поддержки типов исключений:
Функции исключений DAO
Имя | Описание |
---|---|
афкссровдаоексцептион | Создает исключение кдаоексцептион из собственного кода. |
AfxThrowDBException | Создает исключение кдбексцептион из собственного кода. |
MFC предоставляет следующую функцию завершения:
Функции завершения
Имя | Описание |
---|---|
AfxAbort | Вызывается для завершения работы приложения при возникновении неустранимой ошибки. |
Комментарии
Дополнительные сведения см. в статье исключения.
Пример
Требования
CATCH
Параметры
exception_class
Указывает тип исключения для проверки. Список стандартных классов исключений см. в разделе Class CException.
exception_object_pointer_name
Задает имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке catch можно использовать имя указателя. Эта переменная объявлена для вас.
Комментарии
Код обработки исключений может опрашивать объект исключения, если это уместно, чтобы получить дополнительные сведения о конкретной причине исключения. Вызов макроса THROW_LAST для сдвига обработки на следующий внешний кадр исключения. Завершите блок try с помощью макроса END_CATCH.
Указатель объекта исключения создается с помощью макроса. Вам не нужно объявлять его самостоятельно.
Блок catch определяется как область C++, разделенная фигурными скобками. Если объявить переменные в этой области, они будут доступны только в пределах этой области. Это также относится к exception_object_pointer_name.
Дополнительные сведения об исключениях и макросе CATCH см. в статье исключения.
Пример
CATCH_ALL
Параметры
Комментарии
Код обработки исключений может опрашивать объект исключения, если это уместно, чтобы получить дополнительные сведения о конкретной причине исключения. Вызов THROW_LAST макроса для сдвига обработки на следующий внешний кадр исключения. Если вы используете CATCH_ALL, завершите блок try с помощью макроса END_CATCH_ALL.
Блок CATCH_ALL определяется как область C++, разделенная фигурными скобками. Если объявить переменные в этой области, они будут доступны только в пределах этой области.
Дополнительные сведения об исключениях см. в статье исключения.
Пример
Требования
Заголовок AFX. h
AND_CATCH
Параметры
exception_class
Указывает тип исключения для проверки. Список стандартных классов исключений см. в разделе Class CException.
exception_object_pointer_name
Имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке AND_CATCH можно использовать имя указателя. Эта переменная объявлена для вас.
Комментарии
Используйте макрос CATCH для перехвата одного типа исключения, а затем макрос AND_CATCH для перехвата каждого последующего типа. Завершите блок try с помощью макроса END_CATCH.
Пример
Требования
Заголовок AFX. h
AND_CATCH_ALL
Параметры
exception_object_pointer_name
Имя для указателя на объект Exception, который будет создан с помощью макроса. Для доступа к объекту исключения в блоке AND_CATCH_ALL можно использовать имя указателя. Эта переменная объявлена для вас.
Комментарии
Используйте макрос catch для перехвата одного типа исключения, а затем макрос AND_CATCH_ALL для перехвата всех остальных последующих типов. Если вы используете AND_CATCH_ALL, завершите блок try с помощью макроса END_CATCH_ALL.
Блок AND_CATCH_ALL определяется как область C++ (разделенная фигурными скобками). При объявлении переменных в этой области Помните, что они доступны только в пределах этой области.
Требования
Заголовок AFX. h
END_CATCH
Комментарии
Дополнительные сведения о макросе END_CATCH см. в статье исключения.
Требования
Заголовок AFX. h
END_CATCH_ALL
Помечает конец последнего CATCH_ALL88 или AND_CATCH_ALL блока.
Требования
Заголовок AFX. h
THROW (MFC)
Создает указанное исключение.
Параметры
Комментарии
Вызовет прерывание выполнения программы и передает управление соответствующему блоку catch в программе. Если блок catch не указан, то управление передается модулю Библиотека Microsoft Foundation Class, который выводит сообщение об ошибке и завершает работу.
Дополнительные сведения см. в статье исключения.
Требования
Заголовок AFX. h
THROW_LAST
Комментарии
Дополнительные сведения см. в статье исключения.
Пример
Требования
Заголовок AFX. h
AfxThrowArchiveException
Создает исключение архива.
Параметры
cause
Задает целое число, указывающее причину исключения. Список возможных значений см. в разделе карчивиксцептион:: m_cause.
лпсзарчивенаме
Указывает на строку, содержащую имя CArchive объекта, вызвавшего исключение (если доступно).
Требования
Заголовок AFX. h
AfxThrowFileException
Вызывает исключение файла.
Параметры
cause
Задает целое число, указывающее причину исключения. Список возможных значений см. в разделе кфиликсцептион:: m_cause.
лосеррор
Содержит номер ошибки операционной системы (при наличии), который указывает причину исключения. Список кодов ошибок см. в руководстве по операционной системе.
лпсзфиленаме
Указывает на строку, содержащую имя файла, вызвавшего исключение (если доступно).
Комментарии
Вы несете ответственность за определение причины на основе кода ошибки операционной системы.
Требования
Заголовок AFX. h
AfxThrowInvalidArgException
Вызывает исключение недопустимого аргумента.
Синтаксис
Remarks
Эта функция вызывается, когда используются недопустимые аргументы.
Требования
Заголовок: AFX. h
AfxThrowMemoryException
Вызывает исключение памяти.
Комментарии
вызывайте эту функцию, если вызовы к базовым распределителям памяти системы (например, malloc и функция GlobalAlloc Windows) завершаются сбоем. Вам не нужно вызывать его для, new так как new в случае сбоя выделения памяти будет автоматически вызывать исключение памяти.
Требования
Заголовок AFX. h
AfxThrowNotSupportedException
Создает исключение, которое является результатом запроса неподдерживаемой функции.
Требования
Заголовок AFX. h
AfxThrowResourceException
Вызывает исключение ресурса.
Комментарии
эта функция обычно вызывается, когда не удается загрузить Windows ресурс.
Требования
Заголовок AFX. h
AfxThrowUserException
Создает исключение для завершения операции пользователя.
Комментарии
Эта функция обычно вызывается сразу после того, как AfxMessageBox пользователь сообщил об ошибке.
Требования
Заголовок AFX. h
AfxThrowOleDispatchException
Эта функция используется для создания исключения в функции OLE Automation.
Параметры
wCode
Код ошибки, относящийся к вашему приложению.
лпсздескриптион
Описание ошибки текстовом.
ндескриптионид
Идентификатор ресурса для описания ошибки текстовом.
нхелпид
Контекст справки для справки вашего приложения (. Файл HLP).
Комментарии
сведения, предоставленные этой функции, могут отображаться в приложении, управляющем приложением (Microsoft Visual Basic или другом клиентском приложении OLE-автоматизации).
Пример
Требования
Заголовок AFX. h
AfxThrowOleException
Создает объект типа COleException и создает исключение.
Параметры
SC
Код состояния OLE, указывающий причину исключения.
ч
Обрабатывает код результата, указывающий причину исключения.
Комментарии
Версия, принимающая HRESULT в качестве аргумента, преобразует этот код результата в соответствующий SCODE. дополнительные сведения о HRESULT и SCODE см. в разделе структура кодов ошибок COM в Windows SDK.
Требования
Заголовок афксдао. h
AfxThrowDaoException
Вызовите эту функцию, чтобы вызвать исключение типа кдаоексцептион из собственного кода.
Параметры
нафксдаоеррор
Целочисленное значение, представляющее расширенный код ошибки DAO, который может быть одним из значений, перечисленных в разделе кдаоексцептион:: m_nAfxDaoError.
SCODE
Код ошибки OLE из DAO типа SCODE. Дополнительные сведения см. в разделе кдаоексцептион:: m_scode.
Комментарии
Требования
Заголовок афксдб. h
AfxThrowDBException
Вызовите эту функцию, чтобы создать исключение типа CDBException из собственного кода.
Параметры
нреткоде
Значение типа РЕТКОДЕ, определяющее тип ошибки, вызвавшей исключение.
файле
Указатель на CDatabase объект, представляющий соединение с источником данных, с которым связано исключение.
hstmt
Обработчик ODBC ХСТМТ, указывающий маркер инструкции, с которым связано исключение.
Комментарии
Платформа вызывается AfxThrowDBException при получении РЕТКОДЕ ODBC из вызова функции API ODBC и ИНТЕРПРЕТИРУЕТ реткоде как исключительную ситуацию, а не как предполагаемую ошибку. Например, операция доступа к данным может завершиться ошибкой из-за ошибки чтения с диска.
сведения о значениях реткоде, определенных ODBC, см. в главе 8 «получение сведений о состоянии и ошибках» в Windows SDK. Дополнительные сведения о расширениях MFC для этих кодов см. в разделе Class кдбексцептион.
Требования
Заголовок AFX. h
AfxAbort
Функция завершения по умолчанию, предоставляемая MFC.
Комментарии
AfxAbort вызывается внутренне функциями-членами MFC при возникновении неустранимой ошибки, например неперехваченного исключения, которое не может быть обработано. Можно вызвать AfxAbort в редких случаях, когда возникает фатальная ошибка, из-за которой невозможно выполнить восстановление.