Обработка исключений
У этой статьи есть несколько проблем, помогите их исправить: |
Обрабо́тка исключи́тельных ситуа́ций (англ. exception handling) — механизм языков программирования, предназначенный для описания реакции программы на ошибки времени выполнения и другие возможные проблемы (исключения), которые могут возникнуть при выполнении программы и приводят к невозможности (бессмысленности) дальнейшей отработки программой её базового алгоритма. В русском языке также применяется более короткая форма термина: «обработка исключений».
Исключения
Общее понятие исключительной ситуации
Во время выполнения программы могут возникать ситуации, когда состояние внешних данных, устройств ввода-вывода или компьютерной системы в целом делает дальнейшие вычисления в соответствии с базовым алгоритмом невозможными или бессмысленными. Классические примеры подобных ситуаций приведены ниже.
- Целочисленное деление на ноль. Конечного результата у данной операции быть не может, поэтому ни дальнейшие вычисления, ни попытка использования результата деления не приведут к решению задачи.
- Ошибка при попытке считать данные с внешнего устройства. Если данные не удаётся получить, любые дальнейшие запланированные операции с ними бессмысленны.
- Исчерпание доступной памяти. Если в какой-то момент система оказывается не в состоянии выделить достаточный для прикладной программы объём оперативной памяти, программа не сможет работать нормально.
- Появление сигнала аварийного отключения электропитания системы. Прикладную задачу, по всей видимости, решить не удастся, в лучшем случае (при наличии какого-то резерва питания) прикладная программа может позаботиться о сохранении данных.
Виды исключительных ситуаций
Исключительные ситуации, возникающие при работе программы, можно разделить на два основных типа: синхронные и асинхронные, принципы реакции на которые существенно различаются.
- Синхронные исключения могут возникнуть только в определённых, заранее известных точках программы. Так, ошибка чтения файла или коммуникационного канала, нехватка памяти — типичные синхронные исключения, так как возникают они только в операции чтения или в операции выделения памяти соответственно.
- Асинхронные исключения могут возникать в любой момент времени и не зависят от того, какую конкретно инструкцию программы выполняет система. Типичные примеры таких исключений: аварийный отказ питания или поступление новых данных.
Некоторые типы исключений могут быть отнесены как к синхронным, так и к асинхронным. Например, инструкция деления на ноль формально должна приводить к синхронному исключению, так как логически оно возникает именно при выполнении данной команды, но на некоторых платформах за счёт глубокой конвейеризации исключение может фактически оказаться асинхронным.
Обработчики исключений
Общее описание
В отсутствие собственного механизма обработки исключений для прикладных программ наиболее общей реакцией на любую исключительную ситуацию является немедленное прекращение выполнения с выдачей пользователю сообщения о характере исключения. Можно сказать, что в подобных случаях единственным и универсальным обработчиком исключений становится операционная система. Например, в операционную систему Windows встроена утилита Dr. Watson, которая занимается сбором информации о необработанном исключении и её отправкой на специальный сервер компании Microsoft.
Возможно игнорирование исключительной ситуации и продолжение работы, но такая тактика опасна, так как приводит к ошибочным результатам работы программ или возникновению ошибок впоследствии. Например, проигнорировав ошибку чтения из файла блока данных, программа получит в своё распоряжение не те данные, которые она должна была считать, а какие-то другие. Результаты их использования предугадать невозможно.
Обработка исключительных ситуаций самой программой заключается в том, что при возникновении исключительной ситуации управление передаётся некоторому заранее определённому обработчику — блоку кода, процедуре, функции, которые выполняют необходимые действия.
Существует два принципиально разных механизма функционирования обработчиков исключений.
- Обработка с возвратом подразумевает, что обработчик исключения ликвидирует возникшую проблему и приводит программу в состояние, когда она может работать дальше по основному алгоритму. В этом случае после того, как выполнится код обработчика, управление передаётся обратно в ту точку программы, где возникла исключительная ситуация (либо на команду, вызвавшую исключение, либо на следующую за ней, как в некоторых старых диалектах языка BASIC) и выполнение программы продолжается. Обработка с возвратом типична для обработчиков асинхронных исключений (которые обычно возникают по причинам, не связанным прямо с выполняемым кодом), для обработки синхронных исключений она малопригодна.
- Обработка без возврата заключается в том, что после выполнения кода обработчика исключения управление передаётся в некоторое, заранее заданное место программы, и с него продолжается исполнение. То есть, фактически, при возникновении исключения команда, во время работы которой оно возникло, заменяется на безусловный переход к заданному оператору.
Существует два варианта подключения обработчика исключительных ситуаций к программе: структурная и неструктурная обработка исключений.
Неструктурная обработка исключений
Неструктурная обработка исключений реализуется в виде механизма регистрации функций или команд-обработчиков для каждого возможного типа исключения. Язык программирования или его системные библиотеки предоставляют программисту как минимум две стандартные процедуры: регистрации обработчика и разрегистрации обработчика. Вызов первой из них «привязывает» обработчик к определённому исключению, вызов второй — отменяет эту «привязку». Если исключение происходит, выполнение основного кода программы немедленно прерывается и начинается выполнение обработчика. По завершении обработчика управление передаётся либо в некоторую наперёд заданную точку программы, либо обратно в точку возникновения исключения (в зависимости от заданного способа обработки — с возвратом или без). Независимо от того, какая часть программы в данный момент выполняется, на определённое исключение всегда реагирует последний зарегистрированный для него обработчик. В некоторых языках зарегистрированный обработчик сохраняет силу только в пределах текущего блока кода (процедуры, функции), тогда процедура разрегистрации не требуется. Ниже показан условный фрагмент кода программы с неструктурной обработкой исключений:
УстановитьОбработчик(ОшибкаБД, ПерейтиНа ОшБД) // На исключение "ОшибкаБД" установлен обработчик - команда "ПерейтиНа ОшБД" ... // Здесь находятся операторы работы с БД ПерейтиНа СнятьОшБД // Команда безусловного перехода - обход обработчика исключений ОшБД: // метка - сюда произойдёт переход в случае ошибки БД по установленному обработчику ... // Обработчик исключения БД СнятьОшБД: // метка - сюда произойдёт переход, если контролируемый код выполнится без ошибки БД. СнятьОбработчик(ОшибкаБД) // Обработчик снят
Неструктурная обработка — практически единственный вариант для обработки асинхронных исключений, но для синхронных исключений она неудобна: приходится часто вызывать команды установки/снятия обработчиков, всегда остаётся опасность нарушить логику работы программы, пропустив регистрацию или разрегистрацию обработчика.
Структурная обработка исключений
Структурная обработка исключений требует обязательной поддержки со стороны языка программирования — наличия специальных синтаксических конструкций. Такая конструкция содержит блок контролируемого кода и обработчик (обработчики) исключений. Наиболее общий вид такой конструкции (условный):
НачалоБлока ... // Контролируемый код ... если (условие) то СоздатьИсключение Исключение2 ... Обработчик Исключение1 ... // Код обработчика для Исключения1 Обработчик Исключение2 ... // Код обработчика для Исключения2 ОбработчикНеобработанных ... // Код обработки ранее не обработанных исключений КонецБлока
Здесь «НачалоБлока» и «КонецБлока» — ключевые слова, которые ограничивают блок контролируемого кода, а «Обработчик» — начало блока обработки соответствующего исключения. Если внутри блока, от начала до первого обработчика, произойдёт исключение, то произойдёт переход на обработчик, написанный для него, после чего весь блок завершится и исполнение будет продолжено со следующей за ним команды. В некоторых языках нет специальных ключевых слов для ограничения блока контролируемого кода, вместо этого обработчик (обработчики) исключений могут быть встроены в некоторые или во все синтаксические конструкции, объединяющие несколько операторов. Так, например, в языке Ада любой составной оператор (begin — end) может содержать обработчик исключений.
«ОбработчикНеобработанных» — это обработчик исключений, которые не соответствуют ни одному из описанных выше в данном блоке. Обработчики исключений в реальности могут описываться по-разному (один обработчик на все исключения, по одному обработчику на каждый тип исключения), но принципиально они работают одинаково: при возникновении исключения находится первый соответствующий ему обработчик в данном блоке, его код выполняется, после чего выполнение блока завершается. Исключения могут возникать как в результате программных ошибок, так и путём явной их генерации с помощью соответствующей команды (в примере — команда «СоздатьИсключение»). С точки зрения обработчиков такие искусственно созданные исключения ничем не отличаются от любых других.
Блоки обработки исключений могут многократно входить друг в друга, как явно (текстуально), так и неявно (например, в блоке вызывается процедура, которая сама имеет блок обработки исключений). Если ни один из обработчиков в текущем блоке не может обработать исключение, то выполнение данного блока немедленно завершается, и управление передаётся на ближайший подходящий обработчик более высокого уровня иерархии. Это продолжается до тех пор, пока обработчик не найдётся и не обработает исключение или пока исключение не выйдет из обработчиков заданных программистом и не будет передано системному обработчику по умолчанию, аварийно закроющему программу.
Иногда бывает неудобно завершать обработку исключения в текущем блоке, то есть желательно, чтобы при возникновении исключения в текущем блоке обработчик выполнил какие-то действия, но исключение продолжило бы обрабатываться на более высоком уровне (обычно так бывает, когда обработчик данного блока не полностью обрабатывает исключение, а лишь частично). В таких случаях в обработчике исключений генерируется новое исключение или возобновляется, с помощью специальной команды, ранее появившееся. Код обработчиков не является защищённым в данном блоке, поэтому созданное в нём исключение будет обрабатываться в блоках более высокого уровня.
Блоки с гарантированным завершением
Помимо блоков контролируемого кода для обработки исключений, языки программирования могут поддерживать блоки с гарантированным завершением. Их использование оказывается удобным тогда, когда в некотором блоке кода, независимо от того, произошли ли какие-то ошибки, необходимо перед его завершением выполнить определённые действия. Простейший пример: если в процедуре динамически создаётся какой-то локальный объект в памяти, то перед выходом из этой процедуры объект должен быть уничтожен (чтобы избежать утечки памяти), независимо от того, произошли после его создания ошибки или нет. Такая возможность реализуется блоками кода вида:
НачалоБлока ... // Основной код Завершение ... // Код завершения КонецБлока
Заключённые между ключевыми словами «НачалоБлока» и «Завершение» операторы (основной код) выполняются последовательно. Если при их выполнении не возникает исключений, то затем выполняются операторы между ключевыми словами «Завершение» и «КонецБлока» (код завершения). Если же при выполнении основного кода возникает исключение (любое), то сразу же выполняется код завершения, после чего весь блок завершается, а возникшее исключение продолжает существовать и распространяться до тех пор, пока его не перехватит какой-либо блок обработки исключений более высокого уровня.
Принципиальное отличие блока с гарантированным завершением от обработки — то, что он не обрабатывает исключение, а лишь гарантирует выполнение определённого набора операций перед тем, как включится механизм обработки. Блок с гарантированным завершением легко реализуется с помощью обычного механизма структурной обработки (для этого достаточно поставить команду генерации исключения непосредственно перед завершением контролируемого блока и правильно написать код обработчика), но наличие отдельной конструкции позволяет сделать код более прозрачным и защищает от случайных ошибок.
Поддержка в различных языках
Большинство современных языков программирования, такие как Ada, C++, D, Delphi, Objective-C, Java, JavaScript, Eiffel, OCaml, Ruby, Python, Common Lisp, SML, PHP, все языки платформы .NET и др., имеет встроенную поддержку структурной обработки исключений. В этих языках при возникновении исключения, поддерживаемого языком, происходит раскрутка стека вызовов до первого обработчика исключений подходящего типа, и управление передаётся обработчику.
За исключением незначительных различий в синтаксисе существует лишь пара вариантов обработки исключений. В наиболее распространённом из них исключительная ситуация генерируется специальным оператором (throw или raise), а само исключение, с точки зрения программы, представляет собой некоторый объект данных. То есть, генерация исключения состоит из двух этапов: создания объекта-исключения и возбуждения исключительной ситуации с этим объектом в качестве параметра. При этом конструирование такого объекта само по себе выброса исключения не вызывает. В одних языках объектом-исключением может быть объект любого типа данных (в том числе строкой, числом, указателем и так далее), в других — только предопределённого типа-исключения (чаще всего он имеет имя Exception) и, возможно, его производных типов (типов-потомков, если язык поддерживает объектные возможности).
Область действия обработчиков начинается специальным ключевым словом try или просто языковым маркером начала блока (например, begin) и заканчивается перед описанием обработчиков (catch, except, resque). Обработчиков может быть несколько, один за одним, и каждый может указывать тип исключения, который он обрабатывает. Как правило, никакого подбора наиболее подходящего обработчика не производится, и выполняется первый же обработчик, совместимый по типу с исключением. Поэтому порядок следования обработчиков имеет важное значение: если обработчик, совместимый с многими или всеми типами исключений, окажется в тексте прежде специфических обработчиков для конкретных типов, то специфические обработчики не будут использоваться вовсе.
Некоторые языки также допускают специальный блок (else), который выполняется, если ни одного исключения не было сгенерировано в соответствующей области действия. Чаще встречается возможность гарантированного завершения блока кода (finally, ensure). Заметным исключением является Си++, где такой конструкции нет. Вместо неё используется автоматический вызов деструкторов объектов. Вместе с тем существуют нестандартные расширения Си++, поддерживающие и функциональность finally (например в MFC).
В целом обработка исключений может выглядеть следующим образом (в некотором абстрактном языке):
try { line = console.readLine(); if (line.length() == 0) throw new EmptyLineException("Строка, считанная из консоли, пустая!"); console.printLine("Привет, %s!" % line); } catch (EmptyLineException exception) { console.printLine("Привет!"); } catch (Exception exception) { console.printLine("Ошибка: " + exception.message()); } else { console.printLine("Программа выполнилась без исключительных ситуаций"); } finally { console.printLine("Программа завершается"); } В некоторых языках может быть лишь один обработчик, который разбирается с различными типами исключений самостоятельно.
Достоинства и недостатки
Достоинства использования исключений особенно заметно проявляются при разработке библиотек процедур и программных компонентов, ориентированных на массовое использование. В таких случаях разработчик часто не знает, как именно должна обрабатываться исключительная ситуация (при написании универсальной процедуры чтения из файла невозможно заранее предусмотреть реакцию на ошибку, так как эта реакция зависит от использующей процедуру программы), но ему это и не нужно — достаточно сгенерировать исключение, обработчик которого предоставляется реализовать пользователю компонента или процедуры. Единственная альтернатива исключениям в таких случаях — возврат кодов ошибок, которые вынужденно передаются по цепочке между несколькими уровнями программы, пока не доберутся до места обработки, загромождая код и снижая его понятность. Использование исключений в целях контроля ошибок повышает читаемость кода, так как позволяет отделить обработку ошибок от самого алгоритма, и облегчает программирование и использование компонентов других разработчиков. А обработка ошибок может быть централизована в аспектах.
Реализация механизма обработки исключений существенно зависит от языка, и даже компиляторы одного и того же языка на одной и той же платформе могут иметь значительные различия. Это не позволяет прозрачно передавать исключения между частями программы, написанной на разных языках; например, поддерживающие исключения библиотеки обычно непригодны для использования в программах на языках, отличных от тех, для которых они разработаны, и, тем более, на языках, не поддерживающих механизм обработки исключений. Такое состояние существенно ограничивает возможности использования исключений, например, в ОС UNIX и её клонах и под Windows, так как большинство системного ПО и низкоуровневых библиотек этих систем пишется на языке Си, не поддерживающем исключений. Соответственно, для работы с API таких систем с применением исключений приходится писать библиотеки-обёртки, функции которых анализировали бы коды возврата функций API и в нужных случаях генерировали бы исключения.
Поддержка исключений усложняет язык и компилятор. Также она снижает скорость работы программы, так как стоимость обработки исключения, как правило, выше стоимости обработки кода ошибки. Поэтому в местах программы, критичных по скорости, не рекомендуют возбуждать и обрабатывать исключения, хотя в прикладном программировании случаи, когда разница в скорости обработки исключений и кодов возврата действительно существенна, очень редки.
Корректная реализация исключений может быть затруднительной в языках с автоматическим вызовом деструкторов. При возникновении исключения в блоке необходимо автоматически вызвать деструкторы объектов, созданных в этом блоке, но только тех, которые не были ещё удалены обычным порядком. Кроме того, требование прерывания текущей операции при возникновении исключения вступает в противоречие с требованием обязательного автоматического удаления в языках с автодеструкторами: если исключение возникнет в деструкторе, то либо компилятор будет вынужден удалить не полностью освобождённый объект, либо объект останется существующим, то есть возникнет утечка памяти. Вследствие этого генерация неперехватываемых исключений в деструкторах в ряде случаев просто запрещается.
Джоэл Спольски считает, что код, рассчитанный на работу с исключениями, теряет линейность и предсказуемость. Если в классическом коде выходы из блока, процедуры или функции находятся только там, где их явно указал программист, то в коде с исключениями исключение (потенциально) может произойти в любом операторе и анализом самого кода невозможно узнать, где именно исключения могут происходить. В коде же, рассчитанном на исключения, предсказать, в каком месте произойдёт выход из блока кода, невозможно, и любой оператор должен рассматриваться как потенциально последний в блоке, в результате сложность кода возрастает, а надёжность снижается.
Также в сложных программах возникают большие «нагромождения» операторов try ... finally и try ... catch (try ... except), если не использовать аспекты.
Проверяемые исключения
Некоторые проблемы простой обработки исключений
Изначально (например, в C++) не существовало никакой формальной дисциплины описания, генерации и обработки исключений: любое исключение может быть возбуждено в любом месте программы, и, если для него не находится обработчика в стеке вызовов, выполнение программы прерывается аварийно. Если функция (особенно библиотечная) генерирует исключения, то для устойчивой работы использующая её программа должна перехватывать их все. Когда по какой-либо причине одно из возможных исключений оказывается необработанным, будет происходить неожиданное аварийное завершение программы.
С подобными эффектами можно бороться организационными мерами: описывая возможные исключения, возникающие в библиотечных модулях, в соответствующей документации. Но при этом всегда остаётся вероятность пропустить необходимый обработчик из-за случайной ошибки или несоответствия документации коду (что вовсе не редкость). Чтобы полностью исключить потерю обработки исключений, в обработчики приходится специально добавлять ветвь обработки «всех остальных» исключений (которая гарантированно перехватит любые, даже заранее неизвестные исключения), но такой выход не всегда оптимален. Более того, сокрытие всех возможных исключений может привести к ситуации, когда будут скрыты серьёзные и при этом трудно обнаруживаемые ошибки.
Механизм проверяемых исключений
Позже в ряде языков, например, в Java, появились проверяемые исключения. Сущность этого механизма состоит в добавлении в язык следующих правил и ограничений:
- В описании функции (или метода класса) в явном виде перечисляются все типы исключений, которые она может сгенерировать.
- Функция, вызывающая функцию или метод с объявленными исключениями, для каждого из этих исключений обязана либо содержать обработчик, либо, в свою очередь, указывать этот тип как генерируемый ею в своём описании.
- Компилятор проверяет наличие обработчика в теле функции или записи исключения в её заголовке. Реакция на наличие неописанного и необработанного исключения может быть разной. Например, в Java, если компилятор обнаруживает возможность возникновения исключения, которое не описано в заголовке функции и не обрабатывается в ней, программа считается некорректной и не компилируется. В C++ возникновение в функции неописанного и необработанного исключения приводит к немедленному завершению программы; при этом отсутствие у функции списка объявленных исключений обозначает возможность возникновения любых исключений и стандартный порядок их обработки внешним кодом.
Внешне (в языке Java) реализация такого подхода выглядит следующим образом:
int getVarValue(String varName) throws SQLException { ... // код метода, возможно, содержащий вызовы, способные бросить исключение SQLException } // Ошибка при компиляции - исключение не объявлено и не перехвачено int eval1(String expression) { ... int a = prev + getVarValue("abc"); ... } // Правильно — исключение объявлено и будет передаваться дальше int eval2(String expression) throws SQLException { ... int a = prev + getVarValue("abc"); ... } // Правильно — исключение перехватывается внутри метода и наружу не выходит int eval3(String expression) { ... try { int a = prev + getVarValue("abc"); } catch (SQLException ex) { // Обработка исключения } ... } Здесь метод getVarValue объявлен как генерирующий исключение SQLException. Следовательно, любой использующий его метод должен либо перехватить это исключение, либо объявить его как генерируемое. В данном примере метод eval1 приведёт к ошибке компиляции, поскольку вызывает метод getVarValue, но не перехватывает исключение и не объявляет его. Метод eval2 объявляет исключение, а метод eval3 перехватывает и обрабатывает его, оба этих метода корректны в отношении работы с исключением, вызываемым методом getVarValue.
Преимущества и недостатки
Возможно, этот раздел содержит оригинальное исследование. |
Проверяемые исключения снижают количество ситуаций, когда исключение, которое могло быть обработано, вызвало критическую ошибку в программе, поскольку за наличием обработчиков следит компилятор. Это особенно полезно при изменениях кода, когда метод, который не мог ранее выбрасывать исключение типа X, начинает это делать; компилятор автоматически отследит все случаи его использования и проверит наличие соответствующих обработчиков.
Другим полезным качеством проверяемых исключений является то, что они способствуют осмысленному написанию обработчиков: программист явно видит полный и правильный список исключений, которые могут возникнуть в данном месте программы, и может написать на каждое из них осмысленный обработчик вместо того, чтобы создавать «на всякий случай» общий обработчик всех исключений, одинаково реагирующий на все нештатные ситуации.
У проверяемых исключений есть и недостатки.
- Они вынуждают создавать обработчики исключений, с которыми программист в принципе справиться не может, например ошибок ввода-вывода в веб-приложении. Это приводит к появлению «глупых» обработчиков, которые не делают ничего или дублируют системный обработчик критической ошибки (например, выводят стек вызова исключения) и, в итоге, только замусоривают код.
- Становится невозможным добавление нового проверяемого исключения в метод, описанный в библиотеке, поскольку это нарушает обратную совместимость. (Это верно и для небиблиотечных методов, но в этом случае проблема менее существенна, так как весь код, в конечном итоге, доступен и может быть переработан).
Из-за перечисленных недостатков при обязательности использования проверяемых исключений этот механизм часто обходят. Например, многие библиотеки объявляют все методы как выбрасывающие некоторый общий класс исключений (например, Exception), и только на этот тип исключения создаются обработчики. Результатом становится то, что компилятор заставляет писать обработчики исключений даже там, где они объективно не нужны, и становится невозможно определить без чтения исходников, какие именно подклассы декларируемых исключений бросает метод, чтобы навесить на них разные обработчики. Более правильным подходом считается перехват внутри метода новых исключений, порождённых вызываемым кодом, а при необходимости передать исключение дальше — «заворачивание» его в исключение, уже возвращаемое методом. Например, если метод изменили так, что он начинает обращаться к базе данных вместо файловой системы, то он может сам ловить SQLException и выбрасывать вместо него вновь создаваемый IOException, указывая в качестве причины исходное исключение. Обычно рекомендуется изначально объявлять именно те исключения, которые придётся обрабатывать вызывающему коду. Скажем, если метод извлекает входные данные, то для него целесообразно объявить IOException, а если он оперирует SQL-запросами, то, вне зависимости от природы ошибки, он должен объявлять SQLException. В любом случае, набор выбрасываемых методом исключений должен тщательно продумываться. При необходимости имеет смысл создавать собственные классы исключений, наследуя их от Exception или других подходящих проверяемых исключений.
Исключения, не требующие проверки
Невозможно сделать проверяемыми вообще все исключения, так как некоторые исключительные ситуации по своей природе таковы, что их возникновение возможно в любом или почти любом месте программы, а предотвратить их программист не в состоянии. При этом бессмысленно указывать подобные исключения в описании функции, так как это пришлось бы сделать для каждой функции, не делая программу понятнее. В основном это исключения, относящиеся к одному из двух видов:
- Исключения, представляющие собой серьёзные ошибки, которые, «по идее», возникать не должны, и которые в обычных условиях не следует обрабатывать программой. Такие ошибки могут возникать как во внешней относительно программы среде, так и внутри неё. Примером такой ситуации может быть ошибка среды исполнения программы на Java. Она потенциально возможна при исполнении любой команды; за редчайшими исключениями в прикладной программе не может быть осмысленного обработчика подобной ошибки — ведь если среда исполнения работает неверно, на что указывает сам факт исключения, нет никакой гарантии, что и обработчик будет исполнен правильно.
- Исключения времени выполнения, обычно связанные с ошибками программиста. Такие исключения возникают из-за логических ошибок разработчика или недостаточности проверок в коде. Например, ошибка обращения по неинициализированному (нулевому) указателю, как правило, означает, что программист либо пропустил где-то инициализацию переменной, либо при выделении динамической памяти не проверил, действительно ли память была выделена. Как первое, так и второе требует исправления кода программы, а не создания обработчиков.
Выносить подобные ошибки вообще за пределы системы обработки исключений нелогично и неудобно, хотя бы потому, что иногда они всё-таки перехватываются и обрабатываются. Поэтому в системах с проверяемыми исключениями часть типов исключений выводится из-под механизма проверки и работает традиционным образом. В Java это классы исключений, унаследованные от java.lang.Error — фатальные ошибки и java.lang.RuntimeException — ошибки времени выполнения, как правило, связанные с ошибками кодирования или недостаточностью проверок в коде программы (неверный аргумент, обращение по пустой ссылке, выход за границы массива, неверное состояние монитора и т. п.).
Грань между «исправимой» и «фатальной» ошибкой очень условная. Например, ошибка ввода-вывода в настольной программе, как правило, «исправимая», и можно сообщить пользователю об этом и продолжить исполнение программы. В веб-скрипте она же «фатальная» — если она случилась, со средой исполнения что-то нехорошее и нужно остановиться, выведя сообщение.
См. также
- Код ошибки
- Setjmp/longjmp
Примечания
- 13 — Joel on Software (англ.). Дата обращения: 7 октября 2012. Архивировано 22 октября 2012 года.
Ссылки
- Типичные сценарии распространения и обработки исключений
Википедия, чтение, книга, библиотека, поиск, нажмите, истории, книги, статьи, wikipedia, учить, информация, история, скачать, скачать бесплатно, mp3, видео, mp4, 3gp, jpg, jpeg, gif, png, картинка, музыка, песня, фильм, игра, игры, мобильный, телефон, Android, iOS, apple, мобильный телефон, Samsung, iphone, xiomi, xiaomi, redmi, honor, oppo, nokia, sonya, mi, ПК, web, Сеть, компьютер, Информация о Обработка исключений, Что такое Обработка исключений? Что означает Обработка исключений?
U etogo termina sushestvuyut i drugie znacheniya sm Isklyuchenie U etoj stati est neskolko problem pomogite ih ispravit V state ne hvataet ssylok na istochniki sm rekomendacii po poisku Informaciya dolzhna byt proveryaema inache ona mozhet byt udalena Vy mozhete otredaktirovat statyu dobaviv ssylki na avtoritetnye istochniki v vide snosok 29 oktyabrya 2010 V state est spisok istochnikov no ne hvataet snosok Bez snosok slozhno opredelit iz kakogo istochnika vzyato kazhdoe otdelnoe utverzhdenie Vy mozhete uluchshit statyu prostaviv snoski na istochniki podtverzhdayushie informaciyu Svedeniya bez snosok mogut byt udaleny 29 oktyabrya 2010 Pozhalujsta posle ispravleniya problemy isklyuchite eyo iz spiska parametrov Posle ustraneniya vseh nedostatkov etot shablon mozhet byt udalyon lyubym uchastnikom Obrabo tka isklyuchi telnyh situa cij angl exception handling mehanizm yazykov programmirovaniya prednaznachennyj dlya opisaniya reakcii programmy na oshibki vremeni vypolneniya i drugie vozmozhnye problemy isklyucheniya kotorye mogut vozniknut pri vypolnenii programmy i privodyat k nevozmozhnosti bessmyslennosti dalnejshej otrabotki programmoj eyo bazovogo algoritma V russkom yazyke takzhe primenyaetsya bolee korotkaya forma termina obrabotka isklyuchenij IsklyucheniyaObshee ponyatie isklyuchitelnoj situacii Vo vremya vypolneniya programmy mogut voznikat situacii kogda sostoyanie vneshnih dannyh ustrojstv vvoda vyvoda ili kompyuternoj sistemy v celom delaet dalnejshie vychisleniya v sootvetstvii s bazovym algoritmom nevozmozhnymi ili bessmyslennymi Klassicheskie primery podobnyh situacij privedeny nizhe Celochislennoe delenie na nol Konechnogo rezultata u dannoj operacii byt ne mozhet poetomu ni dalnejshie vychisleniya ni popytka ispolzovaniya rezultata deleniya ne privedut k resheniyu zadachi Oshibka pri popytke schitat dannye s vneshnego ustrojstva Esli dannye ne udayotsya poluchit lyubye dalnejshie zaplanirovannye operacii s nimi bessmyslenny Ischerpanie dostupnoj pamyati Esli v kakoj to moment sistema okazyvaetsya ne v sostoyanii vydelit dostatochnyj dlya prikladnoj programmy obyom operativnoj pamyati programma ne smozhet rabotat normalno Poyavlenie signala avarijnogo otklyucheniya elektropitaniya sistemy Prikladnuyu zadachu po vsej vidimosti reshit ne udastsya v luchshem sluchae pri nalichii kakogo to rezerva pitaniya prikladnaya programma mozhet pozabotitsya o sohranenii dannyh Vidy isklyuchitelnyh situacij Isklyuchitelnye situacii voznikayushie pri rabote programmy mozhno razdelit na dva osnovnyh tipa sinhronnye i asinhronnye principy reakcii na kotorye sushestvenno razlichayutsya Sinhronnye isklyucheniya mogut vozniknut tolko v opredelyonnyh zaranee izvestnyh tochkah programmy Tak oshibka chteniya fajla ili kommunikacionnogo kanala nehvatka pamyati tipichnye sinhronnye isklyucheniya tak kak voznikayut oni tolko v operacii chteniya ili v operacii vydeleniya pamyati sootvetstvenno Asinhronnye isklyucheniya mogut voznikat v lyuboj moment vremeni i ne zavisyat ot togo kakuyu konkretno instrukciyu programmy vypolnyaet sistema Tipichnye primery takih isklyuchenij avarijnyj otkaz pitaniya ili postuplenie novyh dannyh Nekotorye tipy isklyuchenij mogut byt otneseny kak k sinhronnym tak i k asinhronnym Naprimer instrukciya deleniya na nol formalno dolzhna privodit k sinhronnomu isklyucheniyu tak kak logicheski ono voznikaet imenno pri vypolnenii dannoj komandy no na nekotoryh platformah za schyot glubokoj konvejerizacii isklyuchenie mozhet fakticheski okazatsya asinhronnym Obrabotchiki isklyuchenijObshee opisanie V otsutstvie sobstvennogo mehanizma obrabotki isklyuchenij dlya prikladnyh programm naibolee obshej reakciej na lyubuyu isklyuchitelnuyu situaciyu yavlyaetsya nemedlennoe prekrashenie vypolneniya s vydachej polzovatelyu soobsheniya o haraktere isklyucheniya Mozhno skazat chto v podobnyh sluchayah edinstvennym i universalnym obrabotchikom isklyuchenij stanovitsya operacionnaya sistema Naprimer v operacionnuyu sistemu Windows vstroena utilita Dr Watson kotoraya zanimaetsya sborom informacii o neobrabotannom isklyuchenii i eyo otpravkoj na specialnyj server kompanii Microsoft Vozmozhno ignorirovanie isklyuchitelnoj situacii i prodolzhenie raboty no takaya taktika opasna tak kak privodit k oshibochnym rezultatam raboty programm ili vozniknoveniyu oshibok vposledstvii Naprimer proignorirovav oshibku chteniya iz fajla bloka dannyh programma poluchit v svoyo rasporyazhenie ne te dannye kotorye ona dolzhna byla schitat a kakie to drugie Rezultaty ih ispolzovaniya predugadat nevozmozhno Obrabotka isklyuchitelnyh situacij samoj programmoj zaklyuchaetsya v tom chto pri vozniknovenii isklyuchitelnoj situacii upravlenie peredayotsya nekotoromu zaranee opredelyonnomu obrabotchiku bloku koda procedure funkcii kotorye vypolnyayut neobhodimye dejstviya Sushestvuet dva principialno raznyh mehanizma funkcionirovaniya obrabotchikov isklyuchenij Obrabotka s vozvratom podrazumevaet chto obrabotchik isklyucheniya likvidiruet voznikshuyu problemu i privodit programmu v sostoyanie kogda ona mozhet rabotat dalshe po osnovnomu algoritmu V etom sluchae posle togo kak vypolnitsya kod obrabotchika upravlenie peredayotsya obratno v tu tochku programmy gde voznikla isklyuchitelnaya situaciya libo na komandu vyzvavshuyu isklyuchenie libo na sleduyushuyu za nej kak v nekotoryh staryh dialektah yazyka BASIC i vypolnenie programmy prodolzhaetsya Obrabotka s vozvratom tipichna dlya obrabotchikov asinhronnyh isklyuchenij kotorye obychno voznikayut po prichinam ne svyazannym pryamo s vypolnyaemym kodom dlya obrabotki sinhronnyh isklyuchenij ona maloprigodna Obrabotka bez vozvrata zaklyuchaetsya v tom chto posle vypolneniya koda obrabotchika isklyucheniya upravlenie peredayotsya v nekotoroe zaranee zadannoe mesto programmy i s nego prodolzhaetsya ispolnenie To est fakticheski pri vozniknovenii isklyucheniya komanda vo vremya raboty kotoroj ono vozniklo zamenyaetsya na bezuslovnyj perehod k zadannomu operatoru Sushestvuet dva varianta podklyucheniya obrabotchika isklyuchitelnyh situacij k programme strukturnaya i nestrukturnaya obrabotka isklyuchenij Nestrukturnaya obrabotka isklyuchenij Nestrukturnaya obrabotka isklyuchenij realizuetsya v vide mehanizma registracii funkcij ili komand obrabotchikov dlya kazhdogo vozmozhnogo tipa isklyucheniya Yazyk programmirovaniya ili ego sistemnye biblioteki predostavlyayut programmistu kak minimum dve standartnye procedury registracii obrabotchika i razregistracii obrabotchika Vyzov pervoj iz nih privyazyvaet obrabotchik k opredelyonnomu isklyucheniyu vyzov vtoroj otmenyaet etu privyazku Esli isklyuchenie proishodit vypolnenie osnovnogo koda programmy nemedlenno preryvaetsya i nachinaetsya vypolnenie obrabotchika Po zavershenii obrabotchika upravlenie peredayotsya libo v nekotoruyu naperyod zadannuyu tochku programmy libo obratno v tochku vozniknoveniya isklyucheniya v zavisimosti ot zadannogo sposoba obrabotki s vozvratom ili bez Nezavisimo ot togo kakaya chast programmy v dannyj moment vypolnyaetsya na opredelyonnoe isklyuchenie vsegda reagiruet poslednij zaregistrirovannyj dlya nego obrabotchik V nekotoryh yazykah zaregistrirovannyj obrabotchik sohranyaet silu tolko v predelah tekushego bloka koda procedury funkcii togda procedura razregistracii ne trebuetsya Nizhe pokazan uslovnyj fragment koda programmy s nestrukturnoj obrabotkoj isklyuchenij UstanovitObrabotchik OshibkaBD PerejtiNa OshBD Na isklyuchenie OshibkaBD ustanovlen obrabotchik komanda PerejtiNa OshBD Zdes nahodyatsya operatory raboty s BD PerejtiNa SnyatOshBD Komanda bezuslovnogo perehoda obhod obrabotchika isklyuchenij OshBD metka syuda proizojdyot perehod v sluchae oshibki BD po ustanovlennomu obrabotchiku Obrabotchik isklyucheniya BD SnyatOshBD metka syuda proizojdyot perehod esli kontroliruemyj kod vypolnitsya bez oshibki BD SnyatObrabotchik OshibkaBD Obrabotchik snyat Nestrukturnaya obrabotka prakticheski edinstvennyj variant dlya obrabotki asinhronnyh isklyuchenij no dlya sinhronnyh isklyuchenij ona neudobna prihoditsya chasto vyzyvat komandy ustanovki snyatiya obrabotchikov vsegda ostayotsya opasnost narushit logiku raboty programmy propustiv registraciyu ili razregistraciyu obrabotchika Strukturnaya obrabotka isklyuchenij Ne sleduet putat so Strukturirovannaya obrabotka isklyuchenij Strukturnaya obrabotka isklyuchenij trebuet obyazatelnoj podderzhki so storony yazyka programmirovaniya nalichiya specialnyh sintaksicheskih konstrukcij Takaya konstrukciya soderzhit blok kontroliruemogo koda i obrabotchik obrabotchiki isklyuchenij Naibolee obshij vid takoj konstrukcii uslovnyj NachaloBloka Kontroliruemyj kod esli uslovie to SozdatIsklyuchenie Isklyuchenie2 Obrabotchik Isklyuchenie1 Kod obrabotchika dlya Isklyucheniya1 Obrabotchik Isklyuchenie2 Kod obrabotchika dlya Isklyucheniya2 ObrabotchikNeobrabotannyh Kod obrabotki ranee ne obrabotannyh isklyuchenij KonecBloka Zdes NachaloBloka i KonecBloka klyuchevye slova kotorye ogranichivayut blok kontroliruemogo koda a Obrabotchik nachalo bloka obrabotki sootvetstvuyushego isklyucheniya Esli vnutri bloka ot nachala do pervogo obrabotchika proizojdyot isklyuchenie to proizojdyot perehod na obrabotchik napisannyj dlya nego posle chego ves blok zavershitsya i ispolnenie budet prodolzheno so sleduyushej za nim komandy V nekotoryh yazykah net specialnyh klyuchevyh slov dlya ogranicheniya bloka kontroliruemogo koda vmesto etogo obrabotchik obrabotchiki isklyuchenij mogut byt vstroeny v nekotorye ili vo vse sintaksicheskie konstrukcii obedinyayushie neskolko operatorov Tak naprimer v yazyke Ada lyuboj sostavnoj operator begin end mozhet soderzhat obrabotchik isklyuchenij ObrabotchikNeobrabotannyh eto obrabotchik isklyuchenij kotorye ne sootvetstvuyut ni odnomu iz opisannyh vyshe v dannom bloke Obrabotchiki isklyuchenij v realnosti mogut opisyvatsya po raznomu odin obrabotchik na vse isklyucheniya po odnomu obrabotchiku na kazhdyj tip isklyucheniya no principialno oni rabotayut odinakovo pri vozniknovenii isklyucheniya nahoditsya pervyj sootvetstvuyushij emu obrabotchik v dannom bloke ego kod vypolnyaetsya posle chego vypolnenie bloka zavershaetsya Isklyucheniya mogut voznikat kak v rezultate programmnyh oshibok tak i putyom yavnoj ih generacii s pomoshyu sootvetstvuyushej komandy v primere komanda SozdatIsklyuchenie S tochki zreniya obrabotchikov takie iskusstvenno sozdannye isklyucheniya nichem ne otlichayutsya ot lyubyh drugih Bloki obrabotki isklyuchenij mogut mnogokratno vhodit drug v druga kak yavno tekstualno tak i neyavno naprimer v bloke vyzyvaetsya procedura kotoraya sama imeet blok obrabotki isklyuchenij Esli ni odin iz obrabotchikov v tekushem bloke ne mozhet obrabotat isklyuchenie to vypolnenie dannogo bloka nemedlenno zavershaetsya i upravlenie peredayotsya na blizhajshij podhodyashij obrabotchik bolee vysokogo urovnya ierarhii Eto prodolzhaetsya do teh por poka obrabotchik ne najdyotsya i ne obrabotaet isklyuchenie ili poka isklyuchenie ne vyjdet iz obrabotchikov zadannyh programmistom i ne budet peredano sistemnomu obrabotchiku po umolchaniyu avarijno zakroyushemu programmu Inogda byvaet neudobno zavershat obrabotku isklyucheniya v tekushem bloke to est zhelatelno chtoby pri vozniknovenii isklyucheniya v tekushem bloke obrabotchik vypolnil kakie to dejstviya no isklyuchenie prodolzhilo by obrabatyvatsya na bolee vysokom urovne obychno tak byvaet kogda obrabotchik dannogo bloka ne polnostyu obrabatyvaet isklyuchenie a lish chastichno V takih sluchayah v obrabotchike isklyuchenij generiruetsya novoe isklyuchenie ili vozobnovlyaetsya s pomoshyu specialnoj komandy ranee poyavivsheesya Kod obrabotchikov ne yavlyaetsya zashishyonnym v dannom bloke poetomu sozdannoe v nyom isklyuchenie budet obrabatyvatsya v blokah bolee vysokogo urovnya Bloki s garantirovannym zaversheniem Pomimo blokov kontroliruemogo koda dlya obrabotki isklyuchenij yazyki programmirovaniya mogut podderzhivat bloki s garantirovannym zaversheniem Ih ispolzovanie okazyvaetsya udobnym togda kogda v nekotorom bloke koda nezavisimo ot togo proizoshli li kakie to oshibki neobhodimo pered ego zaversheniem vypolnit opredelyonnye dejstviya Prostejshij primer esli v procedure dinamicheski sozdayotsya kakoj to lokalnyj obekt v pamyati to pered vyhodom iz etoj procedury obekt dolzhen byt unichtozhen chtoby izbezhat utechki pamyati nezavisimo ot togo proizoshli posle ego sozdaniya oshibki ili net Takaya vozmozhnost realizuetsya blokami koda vida NachaloBloka Osnovnoj kod Zavershenie Kod zaversheniya KonecBloka Zaklyuchyonnye mezhdu klyuchevymi slovami NachaloBloka i Zavershenie operatory osnovnoj kod vypolnyayutsya posledovatelno Esli pri ih vypolnenii ne voznikaet isklyuchenij to zatem vypolnyayutsya operatory mezhdu klyuchevymi slovami Zavershenie i KonecBloka kod zaversheniya Esli zhe pri vypolnenii osnovnogo koda voznikaet isklyuchenie lyuboe to srazu zhe vypolnyaetsya kod zaversheniya posle chego ves blok zavershaetsya a voznikshee isklyuchenie prodolzhaet sushestvovat i rasprostranyatsya do teh por poka ego ne perehvatit kakoj libo blok obrabotki isklyuchenij bolee vysokogo urovnya Principialnoe otlichie bloka s garantirovannym zaversheniem ot obrabotki to chto on ne obrabatyvaet isklyuchenie a lish garantiruet vypolnenie opredelyonnogo nabora operacij pered tem kak vklyuchitsya mehanizm obrabotki Blok s garantirovannym zaversheniem legko realizuetsya s pomoshyu obychnogo mehanizma strukturnoj obrabotki dlya etogo dostatochno postavit komandu generacii isklyucheniya neposredstvenno pered zaversheniem kontroliruemogo bloka i pravilno napisat kod obrabotchika no nalichie otdelnoj konstrukcii pozvolyaet sdelat kod bolee prozrachnym i zashishaet ot sluchajnyh oshibok Podderzhka v razlichnyh yazykahBolshinstvo sovremennyh yazykov programmirovaniya takie kak Ada C D Delphi Objective C Java JavaScript Eiffel OCaml Ruby Python Common Lisp SML PHP vse yazyki platformy NET i dr imeet vstroennuyu podderzhku strukturnoj obrabotki isklyuchenij V etih yazykah pri vozniknovenii isklyucheniya podderzhivaemogo yazykom proishodit raskrutka steka vyzovov do pervogo obrabotchika isklyuchenij podhodyashego tipa i upravlenie peredayotsya obrabotchiku Za isklyucheniem neznachitelnyh razlichij v sintaksise sushestvuet lish para variantov obrabotki isklyuchenij V naibolee rasprostranyonnom iz nih isklyuchitelnaya situaciya generiruetsya specialnym operatorom throw ili raise a samo isklyuchenie s tochki zreniya programmy predstavlyaet soboj nekotoryj obekt dannyh To est generaciya isklyucheniya sostoit iz dvuh etapov sozdaniya obekta isklyucheniya i vozbuzhdeniya isklyuchitelnoj situacii s etim obektom v kachestve parametra Pri etom konstruirovanie takogo obekta samo po sebe vybrosa isklyucheniya ne vyzyvaet V odnih yazykah obektom isklyucheniem mozhet byt obekt lyubogo tipa dannyh v tom chisle strokoj chislom ukazatelem i tak dalee v drugih tolko predopredelyonnogo tipa isklyucheniya chashe vsego on imeet imya Exception i vozmozhno ego proizvodnyh tipov tipov potomkov esli yazyk podderzhivaet obektnye vozmozhnosti Oblast dejstviya obrabotchikov nachinaetsya specialnym klyuchevym slovom try ili prosto yazykovym markerom nachala bloka naprimer begin i zakanchivaetsya pered opisaniem obrabotchikov catch except resque Obrabotchikov mozhet byt neskolko odin za odnim i kazhdyj mozhet ukazyvat tip isklyucheniya kotoryj on obrabatyvaet Kak pravilo nikakogo podbora naibolee podhodyashego obrabotchika ne proizvoditsya i vypolnyaetsya pervyj zhe obrabotchik sovmestimyj po tipu s isklyucheniem Poetomu poryadok sledovaniya obrabotchikov imeet vazhnoe znachenie esli obrabotchik sovmestimyj s mnogimi ili vsemi tipami isklyuchenij okazhetsya v tekste prezhde specificheskih obrabotchikov dlya konkretnyh tipov to specificheskie obrabotchiki ne budut ispolzovatsya vovse Nekotorye yazyki takzhe dopuskayut specialnyj blok else kotoryj vypolnyaetsya esli ni odnogo isklyucheniya ne bylo sgenerirovano v sootvetstvuyushej oblasti dejstviya Chashe vstrechaetsya vozmozhnost garantirovannogo zaversheniya bloka koda finally ensure Zametnym isklyucheniem yavlyaetsya Si gde takoj konstrukcii net Vmesto neyo ispolzuetsya avtomaticheskij vyzov destruktorov obektov Vmeste s tem sushestvuyut nestandartnye rasshireniya Si podderzhivayushie i funkcionalnost finally naprimer v MFC V celom obrabotka isklyuchenij mozhet vyglyadet sleduyushim obrazom v nekotorom abstraktnom yazyke try line console readLine if line length 0 throw new EmptyLineException Stroka schitannaya iz konsoli pustaya console printLine Privet s line catch EmptyLineException exception console printLine Privet catch Exception exception console printLine Oshibka exception message else console printLine Programma vypolnilas bez isklyuchitelnyh situacij finally console printLine Programma zavershaetsya V nekotoryh yazykah mozhet byt lish odin obrabotchik kotoryj razbiraetsya s razlichnymi tipami isklyuchenij samostoyatelno Dostoinstva i nedostatkiDostoinstva ispolzovaniya isklyuchenij osobenno zametno proyavlyayutsya pri razrabotke bibliotek procedur i programmnyh komponentov orientirovannyh na massovoe ispolzovanie V takih sluchayah razrabotchik chasto ne znaet kak imenno dolzhna obrabatyvatsya isklyuchitelnaya situaciya pri napisanii universalnoj procedury chteniya iz fajla nevozmozhno zaranee predusmotret reakciyu na oshibku tak kak eta reakciya zavisit ot ispolzuyushej proceduru programmy no emu eto i ne nuzhno dostatochno sgenerirovat isklyuchenie obrabotchik kotorogo predostavlyaetsya realizovat polzovatelyu komponenta ili procedury Edinstvennaya alternativa isklyucheniyam v takih sluchayah vozvrat kodov oshibok kotorye vynuzhdenno peredayutsya po cepochke mezhdu neskolkimi urovnyami programmy poka ne doberutsya do mesta obrabotki zagromozhdaya kod i snizhaya ego ponyatnost Ispolzovanie isklyuchenij v celyah kontrolya oshibok povyshaet chitaemost koda tak kak pozvolyaet otdelit obrabotku oshibok ot samogo algoritma i oblegchaet programmirovanie i ispolzovanie komponentov drugih razrabotchikov A obrabotka oshibok mozhet byt centralizovana v aspektah Realizaciya mehanizma obrabotki isklyuchenij sushestvenno zavisit ot yazyka i dazhe kompilyatory odnogo i togo zhe yazyka na odnoj i toj zhe platforme mogut imet znachitelnye razlichiya Eto ne pozvolyaet prozrachno peredavat isklyucheniya mezhdu chastyami programmy napisannoj na raznyh yazykah naprimer podderzhivayushie isklyucheniya biblioteki obychno neprigodny dlya ispolzovaniya v programmah na yazykah otlichnyh ot teh dlya kotoryh oni razrabotany i tem bolee na yazykah ne podderzhivayushih mehanizm obrabotki isklyuchenij Takoe sostoyanie sushestvenno ogranichivaet vozmozhnosti ispolzovaniya isklyuchenij naprimer v OS UNIX i eyo klonah i pod Windows tak kak bolshinstvo sistemnogo PO i nizkourovnevyh bibliotek etih sistem pishetsya na yazyke Si ne podderzhivayushem isklyuchenij Sootvetstvenno dlya raboty s API takih sistem s primeneniem isklyuchenij prihoditsya pisat biblioteki obyortki funkcii kotoryh analizirovali by kody vozvrata funkcij API i v nuzhnyh sluchayah generirovali by isklyucheniya Podderzhka isklyuchenij uslozhnyaet yazyk i kompilyator Takzhe ona snizhaet skorost raboty programmy tak kak stoimost obrabotki isklyucheniya kak pravilo vyshe stoimosti obrabotki koda oshibki Poetomu v mestah programmy kritichnyh po skorosti ne rekomenduyut vozbuzhdat i obrabatyvat isklyucheniya hotya v prikladnom programmirovanii sluchai kogda raznica v skorosti obrabotki isklyuchenij i kodov vozvrata dejstvitelno sushestvenna ochen redki Korrektnaya realizaciya isklyuchenij mozhet byt zatrudnitelnoj v yazykah s avtomaticheskim vyzovom destruktorov Pri vozniknovenii isklyucheniya v bloke neobhodimo avtomaticheski vyzvat destruktory obektov sozdannyh v etom bloke no tolko teh kotorye ne byli eshyo udaleny obychnym poryadkom Krome togo trebovanie preryvaniya tekushej operacii pri vozniknovenii isklyucheniya vstupaet v protivorechie s trebovaniem obyazatelnogo avtomaticheskogo udaleniya v yazykah s avtodestruktorami esli isklyuchenie vozniknet v destruktore to libo kompilyator budet vynuzhden udalit ne polnostyu osvobozhdyonnyj obekt libo obekt ostanetsya sushestvuyushim to est vozniknet utechka pamyati Vsledstvie etogo generaciya neperehvatyvaemyh isklyuchenij v destruktorah v ryade sluchaev prosto zapreshaetsya Dzhoel Spolski schitaet chto kod rasschitannyj na rabotu s isklyucheniyami teryaet linejnost i predskazuemost Esli v klassicheskom kode vyhody iz bloka procedury ili funkcii nahodyatsya tolko tam gde ih yavno ukazal programmist to v kode s isklyucheniyami isklyuchenie potencialno mozhet proizojti v lyubom operatore i analizom samogo koda nevozmozhno uznat gde imenno isklyucheniya mogut proishodit V kode zhe rasschitannom na isklyucheniya predskazat v kakom meste proizojdyot vyhod iz bloka koda nevozmozhno i lyuboj operator dolzhen rassmatrivatsya kak potencialno poslednij v bloke v rezultate slozhnost koda vozrastaet a nadyozhnost snizhaetsya Takzhe v slozhnyh programmah voznikayut bolshie nagromozhdeniya operatorov try finally i try catch try except esli ne ispolzovat aspekty Proveryaemye isklyucheniyaNekotorye problemy prostoj obrabotki isklyuchenij Iznachalno naprimer v C ne sushestvovalo nikakoj formalnoj discipliny opisaniya generacii i obrabotki isklyuchenij lyuboe isklyuchenie mozhet byt vozbuzhdeno v lyubom meste programmy i esli dlya nego ne nahoditsya obrabotchika v steke vyzovov vypolnenie programmy preryvaetsya avarijno Esli funkciya osobenno bibliotechnaya generiruet isklyucheniya to dlya ustojchivoj raboty ispolzuyushaya eyo programma dolzhna perehvatyvat ih vse Kogda po kakoj libo prichine odno iz vozmozhnyh isklyuchenij okazyvaetsya neobrabotannym budet proishodit neozhidannoe avarijnoe zavershenie programmy S podobnymi effektami mozhno borotsya organizacionnymi merami opisyvaya vozmozhnye isklyucheniya voznikayushie v bibliotechnyh modulyah v sootvetstvuyushej dokumentacii No pri etom vsegda ostayotsya veroyatnost propustit neobhodimyj obrabotchik iz za sluchajnoj oshibki ili nesootvetstviya dokumentacii kodu chto vovse ne redkost Chtoby polnostyu isklyuchit poteryu obrabotki isklyuchenij v obrabotchiki prihoditsya specialno dobavlyat vetv obrabotki vseh ostalnyh isklyuchenij kotoraya garantirovanno perehvatit lyubye dazhe zaranee neizvestnye isklyucheniya no takoj vyhod ne vsegda optimalen Bolee togo sokrytie vseh vozmozhnyh isklyuchenij mozhet privesti k situacii kogda budut skryty seryoznye i pri etom trudno obnaruzhivaemye oshibki Mehanizm proveryaemyh isklyuchenij Pozzhe v ryade yazykov naprimer v Java poyavilis proveryaemye isklyucheniya Sushnost etogo mehanizma sostoit v dobavlenii v yazyk sleduyushih pravil i ogranichenij V opisanii funkcii ili metoda klassa v yavnom vide perechislyayutsya vse tipy isklyuchenij kotorye ona mozhet sgenerirovat Funkciya vyzyvayushaya funkciyu ili metod s obyavlennymi isklyucheniyami dlya kazhdogo iz etih isklyuchenij obyazana libo soderzhat obrabotchik libo v svoyu ochered ukazyvat etot tip kak generiruemyj eyu v svoyom opisanii Kompilyator proveryaet nalichie obrabotchika v tele funkcii ili zapisi isklyucheniya v eyo zagolovke Reakciya na nalichie neopisannogo i neobrabotannogo isklyucheniya mozhet byt raznoj Naprimer v Java esli kompilyator obnaruzhivaet vozmozhnost vozniknoveniya isklyucheniya kotoroe ne opisano v zagolovke funkcii i ne obrabatyvaetsya v nej programma schitaetsya nekorrektnoj i ne kompiliruetsya V C vozniknovenie v funkcii neopisannogo i neobrabotannogo isklyucheniya privodit k nemedlennomu zaversheniyu programmy pri etom otsutstvie u funkcii spiska obyavlennyh isklyuchenij oboznachaet vozmozhnost vozniknoveniya lyubyh isklyuchenij i standartnyj poryadok ih obrabotki vneshnim kodom Vneshne v yazyke Java realizaciya takogo podhoda vyglyadit sleduyushim obrazom int getVarValue String varName throws SQLException kod metoda vozmozhno soderzhashij vyzovy sposobnye brosit isklyuchenie SQLException Oshibka pri kompilyacii isklyuchenie ne obyavleno i ne perehvacheno int eval1 String expression int a prev getVarValue abc Pravilno isklyuchenie obyavleno i budet peredavatsya dalshe int eval2 String expression throws SQLException int a prev getVarValue abc Pravilno isklyuchenie perehvatyvaetsya vnutri metoda i naruzhu ne vyhodit int eval3 String expression try int a prev getVarValue abc catch SQLException ex Obrabotka isklyucheniya Zdes metod getVarValue obyavlen kak generiruyushij isklyuchenie SQLException Sledovatelno lyuboj ispolzuyushij ego metod dolzhen libo perehvatit eto isklyuchenie libo obyavit ego kak generiruemoe V dannom primere metod eval1 privedyot k oshibke kompilyacii poskolku vyzyvaet metod getVarValue no ne perehvatyvaet isklyuchenie i ne obyavlyaet ego Metod eval2 obyavlyaet isklyuchenie a metod eval3 perehvatyvaet i obrabatyvaet ego oba etih metoda korrektny v otnoshenii raboty s isklyucheniem vyzyvaemym metodom getVarValue Preimushestva i nedostatki Vozmozhno etot razdel soderzhit originalnoe issledovanie Proverte sootvetstvie informacii privedyonnym istochnikam i udalite ili ispravte informaciyu yavlyayushuyusya originalnym issledovaniem V sluchae neobhodimosti podtverdite informaciyu avtoritetnymi istochnikami V protivnom sluchae etot razdel mozhet byt udalyon 17 noyabrya 2013 Proveryaemye isklyucheniya snizhayut kolichestvo situacij kogda isklyuchenie kotoroe moglo byt obrabotano vyzvalo kriticheskuyu oshibku v programme poskolku za nalichiem obrabotchikov sledit kompilyator Eto osobenno polezno pri izmeneniyah koda kogda metod kotoryj ne mog ranee vybrasyvat isklyuchenie tipa X nachinaet eto delat kompilyator avtomaticheski otsledit vse sluchai ego ispolzovaniya i proverit nalichie sootvetstvuyushih obrabotchikov Drugim poleznym kachestvom proveryaemyh isklyuchenij yavlyaetsya to chto oni sposobstvuyut osmyslennomu napisaniyu obrabotchikov programmist yavno vidit polnyj i pravilnyj spisok isklyuchenij kotorye mogut vozniknut v dannom meste programmy i mozhet napisat na kazhdoe iz nih osmyslennyj obrabotchik vmesto togo chtoby sozdavat na vsyakij sluchaj obshij obrabotchik vseh isklyuchenij odinakovo reagiruyushij na vse neshtatnye situacii U proveryaemyh isklyuchenij est i nedostatki Oni vynuzhdayut sozdavat obrabotchiki isklyuchenij s kotorymi programmist v principe spravitsya ne mozhet naprimer oshibok vvoda vyvoda v veb prilozhenii Eto privodit k poyavleniyu glupyh obrabotchikov kotorye ne delayut nichego ili dubliruyut sistemnyj obrabotchik kriticheskoj oshibki naprimer vyvodyat stek vyzova isklyucheniya i v itoge tolko zamusorivayut kod Stanovitsya nevozmozhnym dobavlenie novogo proveryaemogo isklyucheniya v metod opisannyj v biblioteke poskolku eto narushaet obratnuyu sovmestimost Eto verno i dlya nebibliotechnyh metodov no v etom sluchae problema menee sushestvenna tak kak ves kod v konechnom itoge dostupen i mozhet byt pererabotan Iz za perechislennyh nedostatkov pri obyazatelnosti ispolzovaniya proveryaemyh isklyuchenij etot mehanizm chasto obhodyat Naprimer mnogie biblioteki obyavlyayut vse metody kak vybrasyvayushie nekotoryj obshij klass isklyuchenij naprimer Exception i tolko na etot tip isklyucheniya sozdayutsya obrabotchiki Rezultatom stanovitsya to chto kompilyator zastavlyaet pisat obrabotchiki isklyuchenij dazhe tam gde oni obektivno ne nuzhny i stanovitsya nevozmozhno opredelit bez chteniya ishodnikov kakie imenno podklassy deklariruemyh isklyuchenij brosaet metod chtoby navesit na nih raznye obrabotchiki Bolee pravilnym podhodom schitaetsya perehvat vnutri metoda novyh isklyuchenij porozhdyonnyh vyzyvaemym kodom a pri neobhodimosti peredat isklyuchenie dalshe zavorachivanie ego v isklyuchenie uzhe vozvrashaemoe metodom Naprimer esli metod izmenili tak chto on nachinaet obrashatsya k baze dannyh vmesto fajlovoj sistemy to on mozhet sam lovit SQLException i vybrasyvat vmesto nego vnov sozdavaemyj IOException ukazyvaya v kachestve prichiny ishodnoe isklyuchenie Obychno rekomenduetsya iznachalno obyavlyat imenno te isklyucheniya kotorye pridyotsya obrabatyvat vyzyvayushemu kodu Skazhem esli metod izvlekaet vhodnye dannye to dlya nego celesoobrazno obyavit IOException a esli on operiruet SQL zaprosami to vne zavisimosti ot prirody oshibki on dolzhen obyavlyat SQLException V lyubom sluchae nabor vybrasyvaemyh metodom isklyuchenij dolzhen tshatelno produmyvatsya Pri neobhodimosti imeet smysl sozdavat sobstvennye klassy isklyuchenij nasleduya ih ot Exception ili drugih podhodyashih proveryaemyh isklyuchenij Isklyucheniya ne trebuyushie proverki Nevozmozhno sdelat proveryaemymi voobshe vse isklyucheniya tak kak nekotorye isklyuchitelnye situacii po svoej prirode takovy chto ih vozniknovenie vozmozhno v lyubom ili pochti lyubom meste programmy a predotvratit ih programmist ne v sostoyanii Pri etom bessmyslenno ukazyvat podobnye isklyucheniya v opisanii funkcii tak kak eto prishlos by sdelat dlya kazhdoj funkcii ne delaya programmu ponyatnee V osnovnom eto isklyucheniya otnosyashiesya k odnomu iz dvuh vidov Isklyucheniya predstavlyayushie soboj seryoznye oshibki kotorye po idee voznikat ne dolzhny i kotorye v obychnyh usloviyah ne sleduet obrabatyvat programmoj Takie oshibki mogut voznikat kak vo vneshnej otnositelno programmy srede tak i vnutri neyo Primerom takoj situacii mozhet byt oshibka sredy ispolneniya programmy na Java Ona potencialno vozmozhna pri ispolnenii lyuboj komandy za redchajshimi isklyucheniyami v prikladnoj programme ne mozhet byt osmyslennogo obrabotchika podobnoj oshibki ved esli sreda ispolneniya rabotaet neverno na chto ukazyvaet sam fakt isklyucheniya net nikakoj garantii chto i obrabotchik budet ispolnen pravilno Isklyucheniya vremeni vypolneniya obychno svyazannye s oshibkami programmista Takie isklyucheniya voznikayut iz za logicheskih oshibok razrabotchika ili nedostatochnosti proverok v kode Naprimer oshibka obrasheniya po neinicializirovannomu nulevomu ukazatelyu kak pravilo oznachaet chto programmist libo propustil gde to inicializaciyu peremennoj libo pri vydelenii dinamicheskoj pamyati ne proveril dejstvitelno li pamyat byla vydelena Kak pervoe tak i vtoroe trebuet ispravleniya koda programmy a ne sozdaniya obrabotchikov Vynosit podobnye oshibki voobshe za predely sistemy obrabotki isklyuchenij nelogichno i neudobno hotya by potomu chto inogda oni vsyo taki perehvatyvayutsya i obrabatyvayutsya Poetomu v sistemah s proveryaemymi isklyucheniyami chast tipov isklyuchenij vyvoditsya iz pod mehanizma proverki i rabotaet tradicionnym obrazom V Java eto klassy isklyuchenij unasledovannye ot java lang Error fatalnye oshibki i java lang RuntimeException oshibki vremeni vypolneniya kak pravilo svyazannye s oshibkami kodirovaniya ili nedostatochnostyu proverok v kode programmy nevernyj argument obrashenie po pustoj ssylke vyhod za granicy massiva nevernoe sostoyanie monitora i t p Gran mezhdu ispravimoj i fatalnoj oshibkoj ochen uslovnaya Naprimer oshibka vvoda vyvoda v nastolnoj programme kak pravilo ispravimaya i mozhno soobshit polzovatelyu ob etom i prodolzhit ispolnenie programmy V veb skripte ona zhe fatalnaya esli ona sluchilas so sredoj ispolneniya chto to nehoroshee i nuzhno ostanovitsya vyvedya soobshenie Sm takzheKod oshibki Setjmp longjmpPrimechaniya13 Joel on Software angl Data obrasheniya 7 oktyabrya 2012 Arhivirovano 22 oktyabrya 2012 goda SsylkiTipichnye scenarii rasprostraneniya i obrabotki isklyuchenij
