Обработка исключений

редактировать

В вычислениях и компьютерном программировании обработка исключений является обработкой реагирования на возникновение исключений - аномальных или исключительных условий, требующих специальной обработки - во время программы программы. Как правило, исключение прерывает нормальный поток выполнения. Как это делается, зависит от того, является ли это исключение аппаратным или программным, и как реализовано программное исключение. Это обеспечивается специализированными конструкциями языка программирования, аппаратными механизмами, такими как прерывания или операционной системой (OS) межпроцессным взаимодействием (IPC) такие средства, как сигналы. Некоторые исключения, особенно аппаратные, могут обрабатываться настолько изящно, что выполнение может возобновиться с того места, где оно было прервано.

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

Содержание

  • 1 Аппаратное обеспечение
    • 1.1 Аппаратная обработка исключений / прерывания: IEEE 754 с плавающей запятой
  • 2 Средства обработки исключений, предоставляемые операционной системой
  • 3 В программном мощном
    • 3.1 История
    • 3.2 Семантика завершения
    • 3.3 Критика
    • 3.4 Поддержка исключений в языках программирования
    • 3.5 Обработка исключений в иерархиях пользовательского интерфейса
    • 3.6 Реализация обработки исключений
    • 3.7Обработка исключений на основе проекта контрактом
    • 3.8 Неперехваченные исключение
    • 3.9 Статическая проверка исключений
      • 3.9.1 Проверенные исключения
      • 3.9.2 Представление об использовании
    • 3.10 Динамическая проверка исключений
    • 3.11 Синхронность исключений
    • 3.12 Системы условий
      • 3.12. 1 Непрерывные исключения
      • 3.12.2 Перезапускает отдельный механизм от политики
  • 4 См. Также
  • 5 Ссылки
  • 6 Внешние ссылки

Аппаратно

Механизмы аппаратныхисключений обрабатываются ЦП. Он для поддержки, например, обнаружение ошибок и предназначено для перенаправления потока на служебные процедуры обработки ошибок. Состояние до исключения сохраняется, например, в стеке.

Аппаратная обработка исключений / ловушки: IEEE 754 с плавающей запятой

Обработка исключений в IEEE 754 стандартное оборудование с плавающей запятой в целом относится к исключительным условия и определяют исключение как «событие, котороепроисходит, когда операция с некоторыми конкретными операндами не имеет результата, подходящего для каждого разумного приложения. Эта операция может сигнализировать об одном или нескольких исключениях, вызывается по умолчанию или явно запрошено, альтернативная обработка определяемого языка ».

По умолчанию исключение IEEE 754 возобновляется и обрабатывается путем замены предопределенных значений на различные исключения, например бесконечность для деления на ноль исключение ипредоставление флагов состояний для процесса обработки исключений, произошло исключение (см. язык программирования C99 для типичного примера обработки исключений IEEE 754). Флагов состояний, включает: вычисление выражения с использованием быстрого

Стандарт IEEE 754 использует термин «Перехват» для обозначения запуск пользовательской подпрограммы обработки исклю чений в исключительных условиях, проверка наличия прямого испытания флагов состояния; а затем, принеобходимости, вызов более устойчивой числовой реализации. Рекомендуемый стандарт. нет несколько вариантов использования для этого, предварительную подстановку значений не по умолчанию, которое возобновить для краткой обработки устранимых функций.

Стандартное поведение обработки исключений IEEE 754 для возобновления после предварительной замены. значения по умолчанию позволяет избежать связанных с изменением потока управления для числовых исключений. Например, в 1996 году первый полетAriane 5 (Flight 501) закончился катастрофическим взрывом, из политик обработки исключений языка программирования Ada, заключающейся в прерывании вычислений при арифметической ошибке., который в данном случае был преобразованием 64-битного числа с плавающей запятой в 16-битное целое число переполнение. Программисты Ariane Flight 501 защитили только четыре случая из семи критических чисел с вычислительными ограничениями бортового компьютера, что оказалось невернымипредположениями о возможном диапазоне значений для незащищенных чисел, потому что использовал код из Ariane 4, для которого их предположения были правильными. Согласно Уильяму Кахану, потери рейса 501 можно было бы избежать, если бы использовалась политика обработки исключений IEEE 754 с заменой обеспечения по умолчанию, потому что переполнение 64-битного преобразования в 16-битное заставило программное прерывание произошло в фрагмент кода, который оказался совершенноненужным на Ariane 5. В официальном отчете о катастрофе (подготовленной комиссией по расследованию, системе Жаком-Луи Лионсом ) отмечалось, что «основная тема при разработке Ariane 5 упор был сделан на уменьшение случайных отказов. Поставщик инерциальной навигационной системы (SRI) следовал только предоставленной ему в спецификации, в случае обнаружения исключения процессор должен быть остановлен. Произошедшее исключение произошло не из-за случайного сбоя, а из-заошибки проекта. Исключение было обнаружено, но было неправильно обработано, поскольку принято мнение, что программное обеспечение следует считать правильным, пока это с считал, что виноват. [...] Несмотря на то, что сбой произошел из-за систематической ошибки программного обеспечения, могут быть введены механизмы для смягчения этого типа проблемы. Например, компьютеры в SRI могли бы быть предоставлены свои наилучшие пожелания отношения. Есть основания, что программная исключительнаяситуация должна быть разрешена или даже обязательна для остановки процесса при работе с критически важными элементами. Действительно, потеря правильной программы программного обеспечения опасна, потому что одно и то же программное обеспечение работает в обоих модулях SRI. В случае отключения Ariane 501 это произошло к отключению двух еще исправных критических важных единиц оборудования. "

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

Средства обработки исключений, предоставляемые системой

Unix -подобные операционные системы дополнительные средства для обработки исключений программ через IPC. Обычно прерывания, вызванные выполнением процесса, обрабатываются программами обслуживания прерываний, и операционная система может отправить сигнал <218 этот процесс, который мог попросить операционную системузарегистрировать обработчик сигнала, который будет вызываться при возникновении сигнала, или выполнить систему выполнения действия по умолчанию (например, завершение программы). Типичные примеры: SIGSEGV, SIGBUS, SIGILL и SIGFPE.

Другие операционные системы, например, OS / 360 и последующие могут использовать различные подходы вместо или в дополнение к IPC.

Обработка программных программ

Обработка программных исключений и поддержка,предоставляемые инструментами, несколько отличаются от того, что понимается под обработкой исключений на оборудовании, но используются аналогичные концепции. В механизме языка программирования для обработки исключений термин используется в определенном смысле для обозначения структуры данных. Один из механизмов передачи управления или исключения как известен. Считается, что исключение выброшено. Исполнение переведено на «уловку».

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

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

  • Языки, которые предотвращают использование использования в качестве управления потоком: Ada, Java, Modula-3, ML, OCaml,PL / I, Python и Ruby попадают в эту категорию..
  • Языки, которые используются только для обработки ненормальных, непредсказуемых, возможных действий: C ++, C #, Common Lisp, Eiffel и Modula-2.

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

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

История

Программная обработка исключений, разработанная в Лисп в 1960-х и 1970-х годах. Это произошло в LISP 1.5 (1962), где исключения были перехвачены ключевым словом ERRSET, которое возвращало NILв случае ошибки, вместо завершения программы. или заходя в отладчик. Повышение ошибок было введено в MacLisp в конце 1960-х годов с ключевым словом ERR. Это было быстро не только для повышенияошибок, но и для нелокального потока управления, и поэтому было дополнено двумя новыми ключевыми словами, CATCHи THROW(MacLisp, июнь 1972 г.), зарезервировав ERRSETи ERRдля обработки ошибок. Поведение очистки, которое обычно теперь называется "finally", было введено в NIL (новая реализация LISP) в середине-конце 1970-х годов как UNWIND-PROTECT. Затем это было принято в Common Lisp. Современным этим был динамический ветерв схеме, которая обрабатывает исключение при закрытии. Первыми работами по структурированной обработке исключений были Гуденаф (1975a) и Гуденаф (1975b). Вперед обработка исключений получила широкое распространение во многих языках программирования с 1980-х годов.

PL / I использовала исключение с динамической областью видимости, однако более поздние языки использовали исключение с лексической областью видимости. Обработка исключений PL / I включает события,которые не связаны с ошибками, например, внимание, конец, изменение перечисленных чисел. Хотя некоторые более поздние языки исключения, не связанные с ошибками, их использование не распространенным явлением.

Первоначально обработка программных исключений включала как возобновляемые исключения (семантика возобновления), как и большинство аппаратных исключений, так и невозобновляемых исключений (семантика завершения). Однако считается семантика возобновления неэффективной практикой в​​1970-х и 1980-х годах (см. Обсуждение стандартизации C ++, цитируемое ниже) и больше не используется, хотя и такими языками программирования, как Common Lisp, Dylan и PL / I.

Семантика завершения

Механизмы обработки исключений на современных языках обычно возобновляются («семантика завершения») в отличие от аппаратных исключений, которые обычно возобновляются. Это основано на опыте использования обоих, поскольку существуют теоретические аргументы и аргументы в пользу любогорешения; они широко обсуждались во время обсуждения стандартизации C ++ в 1989–1991 годах, в результате чего было принято окончательное решение о семантике. Обоснование такой конструкции механизма C ++ Страуструп отмечает:

[На встрече в Пало-Альто [стандартизация C ++] в ноябре 1991 года мы услышали блестящее резюме аргументов в пользу прекращения семантика, подкрепление как личным опытом., так и данных из Джима Митчелла (из Sun, ранее из Xerox PARC). Джим используетобработку исключений на полдюжине языков в течение 20 лет и был одним из первых сторонников возобновления семантики в качестве одного из разработчиков и разработчиков системы Xerox Cedar / Mesa. Его сообщение было

: «Прекращение предпочтительнее возобновления; это не вопрос, а вопрос многолетнего мнения. Возобновление соблазнительно, но недействительно ».

Он подкрепил это предложение работы с операционными системами. Ключевым примером был Cedar / Mesa: он был написан людьми,которые любили и использовали возобновление, но после десяти лет использования в системе полмиллиона строк осталось только одно использование возобновления - и это был контекстный запрос. На деле возобновление не было необходимости для такого запроса контекста, они удалили его и самое большое увеличение скорости в этой части системы. В каждом случае, когда использовалось возобновление, оно - за десять лет - становилось проблемой. По сути, возобновления отдельные означало неспособность сохранитьуровни абстракции несвязанными.

Критика

Противоположный взгляд на безопасность обработки дал Тони Хоар в 1980 году., описывая язык программирования Ada как имеющий "... множество функций и условных обозначений, многие из них ненужны, а некоторые, например, обработка исключений, даже опасны. [...] Не разрешать этот язык в его Эта ракета сбьется с пути из-за ошибки языка программирования, может быть исследовательской космической ракетой в безвредном полете кВенере: это может быть ядерная боеголовка,

Анализ потока данных из 5 миллионов строк кода Java обнаружил более 1300 дефектов обработки Дополнительные исследования других авторов (1999–2004 гг.). И их собственные результаты. Разработаны в том, что они «скрытые пути потока управления, которые программистам трудно рассуждать».

Go было изначально выпущено с явной опущенной обработкой исключений, и разработчики. Позже к языку был добавлен специальный механизм panic/ recovery, который Go советуют использовать только для неисправных ошибок, которые должны оста, утверждали, что это запутывает поток управления . новить весь процесс.

Исключения, как неструктурированный поток, увеличивают риск утечки ресурсов (например, выход из раздела, заблокированного мьютексом , или временного удержания файла открытым) или несогласованного состояния. Существуют различные методы управления ресурсами при наличии исключений,чаще всего комбинирующие шаблон dispose некоторой способ защиты от откручивания (например, предложение finally), который автоматически освобождает ресурс, когда элемент управления выходит из раздела кода.

Поддержка исключений в языках программирования

Многие компьютерные языки поддерживают встроенную поддержку исключений и обработки исключений. Сюда входят ActionScript, Ada, BlitzMax, C ++, C#, Clojure, COBOL, D, ECMAScript, Eiffel, Java, ML, Object Pascal (например, Delphi, Free Pascal и т.п.), PowerBuilder, Objective-C, OCaml, PHP (начиная с версии 5), PL / I, PL / SQL, Prolog, Python, REALbasic, Ruby, Scala, Seed7, Smalltalk, Tcl, Visual Prolog и большинства языков .NET. Обработкаисключений на этих языках обычно не возобновляется, и, когда возникает исключение, программа выполняет обратный поиск в стеке вызовов функций, пока не будет найден обработчик исключения.

Некоторые языки требуют раскрутки стека по мере продвижения этого поиска. То есть, если функция f, встроенная обработчик H для исключения E, вызывает функцию g, которая, в свою очередь, вызывает функцию h, и исключение E возникает в h, то функции hи g могут быть завершены, а H в f будет обрабатывать E.

Языками обработки исключений без этой раскрутки являются Common Lisp с его системой, PL / I и Smalltalk. Все выполняют обработчик исключений и не раскручивают стек; однако в PL / I, если «ON-модуль» (обработчик исключений) выполняет GOTO из ON-модуля, это раскручивает стек. Обработчик исключений имеет возможность перезапустить вычисление, возобновить или прекратитьвыполнение. Это позволяет программе вычисления в том же месте, где произошла ошибка (например, когда ранее отсутствующий файл стал доступ), или реализовать, ведение журнала, запросы и переменные жидкости поверх механизма обработки исключений (как сделано в Smalltalk). Бестековая реализация языка программирования Mythryl поддерживает постоянную обработку исключений без раскрутки стека.

За исключением незначительных синтаксических различий, используется только пара стилей обработкиисключений. В наиболее популярном стиле запускается специальным оператором (throwили raise) с исключением исключения (например, с Java или Object Pascal) или специальным расширяемым перечислимым типом (например, с Ada или SML). Область для обработчиков исключений начинается с предложения маркера (tryили стартера блока языка, такого как begin) и заканчивается в начале первого предложения обработчика (catch, кроме, спасти). Заэтим может следовать несколько предложений обработчика, и в каждом можно указать, какие типы исключений он обрабатывает и какое имя использует для объекта исключения.

Некоторые ограничения действия допускают предложение (else), которое используется в случае, если исключение не возникло до достижения конца области обработчика.

Более распространенным является связанное предложение (finallyили sure), которое выполняется независимо от того, произошлоли исключение или нет, обычно для освобождения ресурсов, полученных в теле исключения. блок управления. Примечательно, что C ++ не предоставляет эту конструкцию, поскольку он поддерживает технику Resource Acquisition Is Initialization (RAII), которая освобождает ресурсы с помощью деструкторов.

В целом код обработки исключений может выглядеть следующим образом ( в Java -подобном псевдокоде ):

попробуйте {line = console.readLine (); if (line.length () ==0){throw new EmptyLineException («Строка, прочитанная с консоли, была пустой!»); } console.printLine («Привет,% s!»% line); console.printLine («Программа успешно запущена.»); } catch (EmptyLineException e) {console.printLine ("Привет!"); } catch (Исключение e) {console.printLine ("Ошибка:" + e.message ()); } finally {console.printLine ("Программа завершается."); }

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

Согласно статье 2008 года Уэстли Веймера и Джорджа Некула, синтаксис блоков try... finallyв Java является фактор, способствующий дефектам программного обеспечения. Когда метод должен обрабатывать сбор и выпуск 3-5 ресурсов, программисты, очевидно, не хотят вкладывать достаточно блоков из-за проблем с удобочитаемостью, даже если это было бы правильным решением. Можно использовать один блок try... finallyдаже при работе с несколькими ресурсами, но это требует правильного использования контрольных значений, что является еще один распространенный источник ошибок для этого типа проблем. Что касается семантики конструкции try... catch... finallyв целом, Веймер и Некула пишут, что «Хотя try-catch-finally концептуально простой, он имеет наиболее сложное описание выполнения в спецификации языка [Gosling et al. 1996] и требует четырех уровней вложенных «if» в егоофициальном английском описании. Короче говоря, он содержит большое количество угловых случаев, который программисты часто упускают из виду. »

C поддерживает различные средства проверки ошибок, но обычно не считается поддерживающим« обработку исключений », хотя setjmpи longjmpстандартные библиотечные функции могут использоваться для реализации семантики исключений.

Perl имеет дополнительную поддержку для структурированной обработкиисключений.

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

Обработка исключений в иерархиях пользовательского интерфейса

Недавний интерфейсный веб-интерфейс инфраструктуры, такие как React и Vue, ввели механизмы обработки ошибок, при которых ошибки распространяются вверх по иерархии компонентов пользовательскогоинтерфейса аналогично тому, как ошибки распространяются вверх по стеку вызовов при выполнении код. Здесь механизм границы ошибок служит аналогом типичного механизма try-catch. Таким образом, компонент может гарантировать, что ошибки от его дочерних компонентов будут обнаружены и обработаны, а не распространены на родительские компоненты.

Например, в Vue компонент будет обнаруживать ошибки, реализовав errorCaptured

Vue.component ('parent', {template: '', errorCaptured: (err, vm, info) =>alert ('Произошла ошибка');}) Vue.component ('child', {template: '{{cause_error ()}} '})

При таком использовании в разметке:

Ошибка, вызванная дочерним компонентом, перехватывается и обрабатывается родительским компонентом.

Реализация обработки исключений

Реализация обработки исключений в языках программирования обычно требует значительного количества поддержки со стороны как генератора кода, так и системы выполнения ,сопровождающей компилятор. (Это было добавление обработки исключений в C ++, которое завершило полезный срок службы исходного компилятора C ++, Cfront.) Наиболее распространены две схемы. Первая, динамическая регистрация, генерирует код, который постоянно обновляет структуры о состоянии программы с точки зрения обработки исключений. Как правило, это добавляет новый элемент в макет кадра стека , который знает, какие обработчики доступны для функции или метода, связанного сэтим кадром; если выбрано исключение, указатель в макете направляет среду выполнения на соответствующий код обработчика. Этот подход компактен с точки зрения места, но добавляет накладные расходы на выполнение при входе и выходе из кадра. Он обычно использовался во многих реализациях Ada, например, где для многих других языковых функций уже требовалась сложная поддержка генерации и выполнения. Динамическая регистрация, которую довольно просто определить, поддается доказательству правильности.

Вторая схема, реализованная во многих компиляторах C ++ производственного качества, представляет собой подход, управляемый таблицами. Это создает статические таблицы во время времени компиляции и времени связывания, которые связывают диапазоны программного счетчика с состоянием программы в отношении обработки исключений. Затем, если генерируется исключение, система времени выполнения ищет текущее местоположение инструкции в таблицах и определяет, какиеобработчики задействованы и что необходимо сделать. Такой подход сводит к минимуму административные издержки в случае, если исключение не генерируется. Это происходит за счет некоторого пространства, но это пространство может быть выделено под специальные разделы данных, предназначенные только для чтения, которые не загружаются или не перемещаются до тех пор, пока фактически не будет создано исключение. Этот второй подход также превосходит с точки зрения достижения безопасности потоков.

Также были предложены другие схемы определения и реализации. Для языков, поддерживающих метапрограммирование, были усовершенствованы подходы, которые вообще не связаны с накладными расходами (помимо уже существующей поддержки отражения).

Обработка исключений на основе дизайна по контракту

Другой взгляд на исключения основан на принципах проектирования по контракту и поддерживается, в частности, языком Eiffel. Идея состоит в том, чтобыобеспечить более строгую основу для обработки исключений, точно определив, что является «нормальным» и «ненормальным» поведением. В частности, подход основан на двух концепциях:

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

"Принцип безопасной обработки исключений", представленный Бертраном Мейером в Конструирование объектно-ориентированного программного обеспечения, затем утверждает, что существует только два значимые способы реакции подпрограммы при возникновении исключения:

  • Отказ или «организованная паника»: процедура исправляет состояние объекта, восстанавливая инвариант (это «организованная» часть), а затем терпит неудачу (паника), вызывая исключение в вызывающей стороне (чтобы не игнорировать ненормальное событие).
  • Retry: процедура снова пробует алгоритм, обычно после изменения некоторых значений, так что у следующей попытки будет больше шансов на успех.

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

Вот пример, выраженный в синтаксисе Eiffel. Предполагается, что процедура send_fastобычно является лучшим способом отправки сообщения, но она может дать сбой, вызвав исключение; если это так, алгоритм затем использует send_slow, что снижает частоту сбоев. Если send_slowзавершается неудачно, процедура sendв целом должна завершиться ошибкой, в результате чего вызывающая сторонаполучит исключение.

send (m: MESSAGE) is - Отправить m через быстрое соединение, если возможно, в противном случае через медленное соединение. local try_fast, try_slow: BOOLEAN делать, если try_fast, затем try_slow: = True send_slow (m) else try_fast: = True send_fast (m) end rescue, если не try_slow, затем повторять конец end

Логические локальные переменные инициализируются значением False в начале. Если send_fastзавершится неудачно, тело (предложение do) будетвыполнено снова, что приведет к выполнению send_slow. Если это выполнение send_slowзавершается неудачно, предложение rescueбудет выполнено до конца без retry(без предложения elseв последнем , если), что приведет к сбою выполнения подпрограммы в целом.

Этот подход имеет достоинство в том, что четко определяет, что такое «нормальный» и «ненормальный» случаи: ненормальный случай, вызывающий исключение, - это тот, в которомпроцедура не может выполнить свой контракт. Он определяет четкое распределение ролей: предложение do(нормальное тело) отвечает за достижение или попытку выполнения контракта процедуры; Предложение rescueотвечает за восстановление контекста и перезапуск процесса, если это имеет шанс на успех, но не за выполнение каких-либо фактических вычислений.

Хотя исключения в Eiffel имеют довольно ясную философию, Кинири (2006) критикует их реализацию, потому что «Исключения,которые являются частью определения языка, представлены значениями INTEGER, определяемые разработчиком исключения - значениями STRING. [...] Кроме того, поскольку они являются базовыми значениями, а не объектами, они не имеют внутренней семантики, кроме той, которая выражена во вспомогательной подпрограмме, которая обязательно не может быть надежной из-за действующей перегрузки представления (например, нельзя различать два целых числа одного и того же значение). "

Неперехваченныеисключения

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

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

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

Этот обработчик неперехваченных исключений по умолчанию может быть переопределен либо глобально, либо для каждого потока, например, для обеспечения альтернативного ведения журнала или отчетов конечного пользователя о неперехваченных исключениях, или для перезапуска потоков, которые завершаются из-занеперехваченного исключения. Например, в Java это делается для одного потока через Thread.setUncaughtExceptionHandler и глобально через Thread.setDefaultUncaughtExceptionHandler ; in Python this is done by modifying sys.excepthook .

Static checking of exceptions

Checked exceptions

The designers of Java devised checked exceptions, which are a special set of exceptions. The checked exceptions that a method may raise are part of the mполе констант связанных классов. "

Проверенные исключения связаны со средствами проверки исключений, которые существуют для языка программирования OCaml. Внешний инструмент для OCaml невидим (т. е. не требует какой-либо синтаксической аннотации) и необязательные (т.е. можно скомпилировать и запустить программу без проверки исключений, хотя это не рекомендуется для производственного кода).

Язык программирования CLU имел особенность с интерфейсом ближе к что Java представила позже. Функция может вызывать только исключения, перечисленные в ее типе, но любая утечка исключений из вызываемых функций будет автоматически превращаться в единственное исключение времени выполнения, сбой, вместо того, чтобы приводить к ошибке времени компиляции. Позже Модула-3 имеет похожую особенность. Эти функции не являются проверкой времени компиляции (по состоянию на 2006 г.).включены в основные языки программирования, кроме Java.

Ранние версии C ++ В язык программирования включен дополнительный механизм для проверенных исключений, называемый спецификациями исключений. По умолчанию любая функция могла генерировать любое исключение, но это было ограничено предложением throw, добавленным к сигнатуре функции, в котором указывается, какие исключения может вызывать функция. Спецификации исключений не применялись во время компиляции. Нарушения привелик вызову глобальной функции std :: неожиданно. Может быть дана пустая спецификация исключения, что означает, что функция не вызовет исключения. Это не было сделано по умолчанию, когда в язык была добавлена ​​обработка исключений, потому что это потребовало бы слишком большой модификации существующего кода, затруднило бы взаимодействие с кодом, написанным на других языках, и могло бы соблазнить программистов написать слишком много обработчиков на локальном уровне. уровень. Однакоявноеиспользование пустых спецификаций исключений может позволить компиляторам C ++ выполнять значительную оптимизацию кода и компоновки стека, которую обычно необходимо подавлять, когда обработка исключений может происходить в функции. Некоторые аналитики считали труднодостижимым правильное использование спецификаций исключений в C ++. В недавнем стандарте языка C ++ (C ++ 11 ) такое использование спецификаций исключений, как указано в версии стандарта C ++ 03, было устаревшим и был удален из языка в C ++ 17. Функция, которая не будет генерировать никаких исключений, теперь может быть обозначена ключевым словом noexcept.

В отличие от Java, такие языки, как C #, не требуют объявления каких-либо типов исключения. Согласно Ханспетеру Мёссенбёку, отсутствие различия между вызываемыми (проверяемыми) исключениями и исключениями, которые не следует вызывать (непроверенными), делает написанную программу более удобной, но менее надежной,поскольку неперехваченное исключение приводит к прерыванию с ошибкой. трассировка стека. Кинири (2006), однако, отмечает, что Java JDK (версия 1.4.1) генерирует большое количество непроверенных исключений: одно на каждые 140 строк кода, тогда как Эйфель использует их гораздо реже, с одним выбросом на 4600 строк кода. Кинири также пишет: «Как известно любому Java-программисту, объем кода try catch в типичном приложении Java иногда больше, чем сопоставимый код,необходимый для явного формального параметра и повторной проверки значений. urn на других языках. Фактически, среди опытных программ Java-программистов существует общее мнение, что работа с проверенными исключениями почти так же неприятна, как и написание документации. Это приводит к обилию проверенных, но игнорируемых исключений ". Также отмечает, что разработчики C # явно находились под данной областью пользовательского опыта, и им приписывается следующая цитата (через Эрика Ганнерсона):

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

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

«Предложение бросает, по крайней мере, способ его реализации в Java, не обязательно заставляет вас обрабатыватьисключение, но если вы не обрабатываете их, она, чтобы не проверять исключение в качестве языковых функций в C #. Это требует, чтобы вы выполнили ее улов точно, какие исключения могут пройти. сключения или помещает их в свой собственный пункт бросков. Чтобы обойти это требование, люди совершают нелепые вещи. Например, они украшают каждый метод «выдает исключение». Это полностью лишает возможности эту функцию, и вы просто заставляете программиста писать еще больше суетной чуши. Это никому непомогает ».

Представления об использовании

Проверенные исключения могут во время компиляции снизить частоту появления необработанных исключений во время времени выполнения в данном приложении. Непроверенные исключения (такие как объекты Java RuntimeExceptionи Error) остаются необработанными.

Однако для проверенных исключений могут потребоваться подробные объявления бросает, раскрывающие детали и уменьшающиеинкапсуляцию, или проиграть плохо продуманное кодирование try / catchблоки, которые могут скрывать допустимые исключения от соответствующих обработчиков. Рассмотрим рост кодовой базы с течением времени. Интерфейс может быть объявлен так, чтобы генерировать исключение X и Y. В более поздней версии кода, если кто-то хочет генерировать исключение Z, это сделает новый код совместимым с предыдущими использованиями. Кроме того, с шаблоном адаптера , в которомодна часть кода объявляет интерфейс, который реализует другой код, код может быть подключен и вызван, код адаптера может иметь богатый набор исключений для описания проблем, но объявен использовать специальные функции в интерфейсе.

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

Использование вызывает исключение объявленияили catch (Exception e)обычно достаточно для выполнения проверки в Java. Хотяэто может иметь определенное применение, оно по существу обходит механизм проверенных исключений, который Oracle не одобряет.

Непроверенные типы исключений, обычно не должны обрабатываться, за исключением, возможно, крайних уровней области видимости. Они часто предоставляют себя сценарии, которые не позволяют восстановить: RuntimeExceptionчасто отражают программные дефекты, а Errorобычно обозначают собой неисправные сбои JVM. Даже на языке, который поддерживаетпроверенные исключения, бывают случаи, когда использование проверенных исключений неуместно.

Динамическая проверка исключений

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

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

В средах среды выполнения, таких как Java или .NET, существуют инструменты, которые подключаются к механизму выполнения и каждый раз, когда возникает интересующее исключение, они записывают отладочная информация, которая существовалав памяти на момент создания исключения (значения стека снабжения и куча ). Эти инструменты называются автоматизированной обработкой исключений или инструментами перехвата ошибок и механизмов об основных причинах исключений.

Синхронность исключений

Синхронность исключений в некоторой степени связанных с концепцией проверенных исключений. Синхронные операторе в конкретном программном режиме, тогда как асинхронные исключения возникатьпрактически где угодно. Отсюда следует, что компилятор не может требовать асинхронной обработки исключений. С ними также сложно программировать. Примеры естественно асинхронных событий пакетие Ctrl-C для прерывания программы и получения сигнала , как «стоп» или «приостановить», от другого потока выполнения.

Языки программирования обычно решают эту проблему, ограничивая асинхронность, например, Java не рекомендует использовать исключение ThreadDeath, котороеиспользовалось для того, чтобы один поток мог останавливать другой другой. Вместо этого могут быть полуасинхронные исключения, которые работают только в подходящих местах программы или синхронно.

Системы условий

Common Lisp, Dylan и Smalltalk имеют (см. Common Lisp Condition System ), которые охватывают вышеупомянутые системы обработки исключений. В этих языках или средах появление условий («обобщение ошибки» согласно Кент Питман )подразумевает вызов функции, и только в конце обработчика исключений может быть принято решение развернуть стек..

Условия являются обобщением исключений. Когда возникает условие, ищется и выбирается соответствующий обработчик условия в порядке стека для обработки условий. Условия, которые не уменьшают себя, могут безопасно остаться без обработки; их единственной целью может быть распространение подсказок или предупреждений для пользователя.

Непрерывные исключения

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

Примером является условием ENDPAGE в PL / I; блок ON может записать строки завершения страницы и строки заголовка для следующей страницы, а затем пропустить, чтобы возобновить выполнение прерванного кода.

Перезапускает отдельный механизм отполитики

Обработка условий, кроме того, обеспечивает отдельный механизм от политики. Перезапуск предлагает механизмы восстановления после ошибки, но не выбирает, какой механизм подходит в данной ситуации. Это область обработчика условий, (который находится в коде более высокого уровня) имеет доступ к более широкому представлению.

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

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

См. также

Ссылки

Внешние ссылки

Последняя правка сделана 2021-05-19 09:29:50
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте