Обробка виключень

Обробка виняткових ситуацій ( англ. exception handling ) - Механізм мов програмування, призначений для опису реакції програми на помилки часу виконання та інші можливі проблеми (виключення), які можуть виникнути при виконанні програми і призводять до неможливості (безглуздості) подальшої відпрацювання програмою її базового алгоритму. У російській мові також застосовується більш коротка форма терміна: "обробка виключень".


1. Винятки

1.1. Загальне поняття виняткової ситуації

Під час виконання програми можуть виникати ситуації, коли стан даних, пристроїв введення-виведення або комп'ютерної системи в цілому робить подальші обчислення відповідно до базового алгоритмом неможливими або безглуздими. Класичні приклади подібних ситуацій наведені нижче.

  • Цілочисельне ділення на нуль. Результату у операції бути не може, тому ні подальші обчислення, ні спроба використання результату ділення не приведуть до вирішення завдання.
  • Помилка при спробі вважати дані з зовнішнього пристрою. Якщо дані не вдається ввести, будь-які подальші заплановані операції з ними безглузді.
  • Вичерпання доступної пам'яті. Якщо в якийсь момент система виявляється не в змозі виділити достатній для прикладної програми обсяг оперативної пам'яті, програма не зможе працювати нормально.
  • Поява сигналу аварійного відключення електроживлення системи. Прикладну задачу, по всій видимості, вирішити не вдасться, в кращому випадку (при наявності якогось резерву харчування) прикладна програма може подбати про збереження даних.
  • Поява на вході комунікаційного каналу даних, що вимагають негайного зчитування. Чим би не займалася в цей момент програма, вона повинна перейти до читання даних, щоб не втратити інформацію, що надійшла.

1.2. Види виняткових ситуацій

Виняткові ситуації, що виникають при роботі програми, можна розділити на два основних типи: синхронні і асинхронні, принципи реакції на які істотно розрізняються.

  • Синхронні виключення можуть виникнути тільки в певних, заздалегідь відомих точках програми. Так, помилка читання файлу або комунікаційного каналу, нестача пам'яті - типові синхронні виключення, тому що виникають вони тільки в операції читання з файлу або з каналу або в операції виділення пам'яті відповідно.
  • Асинхронні виключення можуть виникати в будь-який момент часу і не залежать від того, яку конкретно інструкцію програми виконує система. Типові приклади таких винятків: аварійний відмова харчування або надходження нових даних.

Деякі типи винятків можуть бути віднесені як до синхронних, так і до асинхронним. Наприклад, інструкція ділення на нуль формально повинна приводити до синхронного виключенню, оскільки логічно воно виникає саме при виконанні даної команди, але на деяких платформах за рахунок глибокої конвейеризации виключення може фактично виявитися асинхронним.


2. Обробники винятків

2.1. Загальний опис

У відсутність власного механізму обробки виключень для прикладних програм найбільш загальною реакцією на будь-яку виняткову ситуацію є негайне припинення виконання з видачею користувачеві повідомлення про характер винятку. Можна сказати, що в подібних випадках єдиним і універсальним обробником винятків стає операційна система. Наприклад, в операційну систему Windows вбудована утиліта Dr.Watson, яка займається збором інформації про необробленому виключення і її відправкою на спеціальний сервер компанії Microsoft.

Можливо ігнорування виняткової ситуації і продовження роботи, але така тактика небезпечна, оскільки призводить до помилкових результатів роботи програм або виникнення помилок згодом. Наприклад, проігнорувавши помилку читання з файлу блоку даних, програма отримає в своє розпорядження не ті дані, які вона повинна була вважати, а якісь інші. Результати їх використання вгадати неможливо.

Обробка виняткових ситуацій самою програмою полягає в тому, що при виникненні виняткової ситуації управління передається деякого заздалегідь визначеному обробникові - блоку коду, процедурі, функції, які виконують необхідні дії.

Існує два принципово різних механізму функціонування обробників виключень.

  • Обробка з поверненням увазі, що обробник виключення ліквідує проблему і призводить програму в стан, коли вона може працювати далі за основним алгоритмом. У цьому випадку після того, як виконається код обробника, управління передається назад в ту точку програми, де виникла виняткова ситуація (або на команду, яка викликала виняток, або на наступну за нею, як в деяких старих діалектах мови BASIC) і виконання програми продовжується. Обробка з поверненням типова для обробників асинхронних винятків (які зазвичай виникають з причин, не пов'язаних прямо з виконуваним кодом), для обробки синхронних винятків вона малопридатна.
  • Обробка без повернення полягає в тому, що після виконання коду обробника виключення управління передається в деякий, заздалегідь задане місце програми, і з нього продовжується виконання. Тобто, фактично, при виникненні виключення команда, під час роботи якої воно виникло, замінюється на безумовний перехід до заданого оператору.

Існує два варіанти підключення обробника виняткових ситуацій до програми: структурні та неструктурні обробка виключень.


2.2. Неструктурних обробка виключень

Неструктурних обробка виключень реалізується у вигляді механізму реєстрації функцій або команд-обробників для кожного можливого типу виключення. Мова програмування або його системні бібліотеки надають програмісту як мінімум дві стандартні процедури: реєстрації обробника і разрегістраціі обробника. Виклик першої з них "прив'язує" обробник до певного виключенню, виклик другий - скасовує цю "прив'язку". Якщо виключення відбувається, виконання основного коду програми негайно переривається і починається виконання обробника. По завершенні обробника управління передається або в деяку наперед задану крапку програми, або назад в точку виникнення виключення (в залежності від заданого способу обробки - з поверненням або без). Незалежно від того, яка частина програми в даний момент виконується, на певний виняток завжди реагує останній зареєстрований для нього обробник. У деяких мовах зареєстрований обробник зберігає силу тільки в межах поточного блоку коду (процедури, функції), тоді процедура разрегістраціі не потрібно. Нижче показаний умовний фрагмент коду програми з неструктурної обробкою виключень:

 УстановитьОбработчик(ОшибкаБД, ПерейтиНа ОшБД) // На исключение "ОшибкаБД" установлен обработчик - команда "ПерейтиНа ОшБД" ... // Здесь находятся операторы работы с БД ПерейтиНа СнятьОшБД // Команда безусловного перехода - обход обработчика исключений ОшБД: // метка - сюда произойдёт переход в случае ошибки БД по установленному обработчику ... // Обработчик исключения БД СнятьОшБД: // метка - сюда произойдёт переход, если контролируемый код выполнится без ошибки БД. СнятьОбработчик(ОшибкаБД) // Обработчик снят 

Неструктурних обробка - практично єдиний варіант для обробки асинхронних винятків, але для синхронних винятків вона незручна: доводиться часто викликати команди установки / зняття обробників, завжди залишається небезпека порушити логіку роботи програми, пропустивши реєстрацію або разрегістрацію обробника.


2.3. Структурна обробка виключень

Структурна обробка виключень вимагає обов'язкової підтримки з боку мови програмування - наявності спеціальних синтаксичних конструкцій. Така конструкція містить блок контрольованого коду і обробник (обробники) винятків. Найбільш загальний вигляд такої конструкції (умовний):

  НачалоБлока ... // Контролируемый код ... если (условие) то СоздатьИсключение Исключение2 ... Обработчик Исключение1 ... // Код обработчика для Исключения1 Обработчик Исключение2 ... // Код обработчика для Исключения2 ОбработчикНеобработанных ... // Код обработки ранее не обработанных исключений КонецБлока 

Тут "НачалоБлока" і "КонецБлока" - ключові слова, які обмежують блок контрольованого коду, а "Оброблювач" - початок блоку обробки відповідного виключення. Якщо всередині блоку, від початку до першого обробника, відбудеться виняток, то відбудеться перехід на обробник, написаний для нього, після чого весь блок завершиться і виконання буде продовжено з наступною за ним команди. У деяких мовах немає спеціальних ключових слів для обмеження блоку контрольованого коду, замість цього обробник (обробники) винятків можуть бути вбудовані в деякі або всі синтаксичні конструкції, що поєднують кілька операторів. Так, наприклад, в мові Ада будь складений оператор (begin - end) може містити обробник виключень.

"ОбработчікНеобработанних" - це оброблювач виключень, які не відповідають жодному з описаних вище в цьому блоці. Обробники винятків в реальності можуть описуватися по-різному (один обробник на всі винятки, по одному обробникові на кожен тип виняток), але принципово вони працюють однаково: при виникненні виключення перебуває перший відповідний йому обробник в даному блоці, його код виконується, після чого виконання блоку завершується. Винятки можуть виникати як в результаті програмних помилок, так і шляхом явною їх генерації за допомогою відповідної команди (у прикладі - команда "СоздатьІсключеніе"). З точки зору обробників такі штучно створені виключення нічим не відрізняються від будь-яких інших.

Блоки обробки виключень можуть багаторазово входити один в одного, як явно (текстуально), так і неявно (наприклад, у блоці викликається процедура, яка сама має блок обробки виключень). Якщо жоден з обробників в поточному блоці не може обробити виняток, то виконання даного блоку негайно завершується, і управління передається на найближчий підходящий оброблювач більш високого рівня ієрархії. Це продовжується до тих пір, поки обробник не знайдеться і не обробить виключення або поки не вийде з обробників заданих програмістом і не буде передано системному обробникові за замовчуванням, аварійно закроющему програму.

Іноді буває незручно завершувати обробку виключення в поточному блоці, тобто бажано, щоб при виникненні виключення в поточному блоці обробник виконав якісь дії, але виключення продовжило б оброблятися на більш високому рівні (зазвичай так буває, коли обробник даного блоку не повністю обробляє виключення , а лише частково). У таких випадках в обробнику винятків генерується нове виключення або відновлюється з допомогою спеціальної команди раніше з'явилося. Код обробників не є захищеним в даному блоці, тому створене в ньому виключення буде оброблятися в блоках більш високого рівня.


2.4. Блоки з гарантованим завершенням

Крім блоків контрольованого коду для обробки винятків, мови програмування можуть підтримувати блоки з гарантованим завершенням. Їх використання виявляється зручним тоді, коли в деякому блоці коду, незалежно від того, чи відбулися якісь помилки, необхідно перед його завершенням виконати певні дії. Найпростіший приклад: якщо в процедурі динамічно створюється якийсь локальний об'єкт в пам'яті, то перед виходом з цієї процедури об'єкт повинен бути знищений (щоб уникнути витоку пам'яті), незалежно від того, відбулися після його створення помилки чи ні. Така можливість реалізується блоками коду виду:

  НачалоБлока ... // Основной код Завершение ... // Код завершения КонецБлока 

Укладені між ключовими словами "НачалоБлока" і "Завершення" оператори (основний код) виконуються послідовно. Якщо при виконанні їх не виникає винятків, то потім виконуються оператори між ключовими словами "Завершення" і "КонецБлока" (код завершення). Якщо ж при виконанні основного коду виникає виключення (будь-яке), то відразу ж виконується код завершення, після чого весь блок завершується, а виникле виключення продовжує існувати і розповсюджуватися до тих пір, поки його не перехопить небудь блок обробки виключень більш високого рівня.

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


3. Підтримка в різних мовах

Більшість сучасних мов програмування, такі як 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  (  "Програма завершується"  )  ;  } 

У деяких мовах може бути лише один обробник, який розбирається з різними типами винятків самостійно.


4. Переваги і недоліки

Переваги використання винятків особливо помітно проявляються при розробці бібліотек процедур і програмних компонентів, орієнтованих на масове використання. У таких випадках розробник часто не знає, як саме повинна оброблятися виняткова ситуація (при написанні універсальної процедури читання з файлу неможливо заздалегідь передбачити реакцію на помилку, так як ця реакція залежить від використовує процедуру програми), але йому це і не потрібно - достатньо згенерувати виключення , обробник якого надається реалізувати користувачеві компонента або процедури. Єдина альтернатива виключень в таких випадках - повернення кодів помилок, які вимушено передаються по ланцюжку між кількома рівнями програми, поки не дістануться до місця обробки, захаращуючи код і знижуючи його зрозумілість. Використання виключень з метою контролю помилок підвищує читаність коду, так як дозволяє відокремити обробку помилок від самого алгоритму, і полегшує програмування та використання компонентів інших розробників. А обробка помилок може бути централізованою в аспектах.

На жаль, реалізація механізму обробки виключень істотно залежить від мови, і навіть компілятори одного і того ж мови на одній і тій же платформі можуть мати значні відмінності. Це не дозволяє прозоро передавати винятку між частинами програми, написаними на різних мовах; наприклад, підтримують виключення бібліотеки зазвичай непридатні для використання в програмах на мовах, відмінних від тих, для яких вони розроблені, і, тим більше, на мовах, що не підтримують механізм обробки винятків. Такий стан суттєво обмежує можливості використання винятків, наприклад, в ОС UNIX і її клонах і під Windows, так як більшість системного ПЗ і низькорівневих бібліотек цих систем пишеться на мові Сі, що не підтримує винятків. Відповідно, для роботи з API таких систем із застосуванням винятків доводиться писати бібліотеки-врапперов, функції яких аналізували б коди повернення функцій API і в потрібних випадках генерували виключення.

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

Коректна реалізація винятків може бути скрутною в мовах з автоматичним викликом деструкторів. При виникненні виключення в блоці необхідно автоматично викликати деструктори об'єктів, створених в даному блоці, але тільки тих, які не були ще видалені звичайним порядком. Крім того, вимога переривання поточної операції при виникненні виключення вступає в протиріччя з вимогою обов'язкового автоматичного видалення в мовах з автодеструкторамі: якщо виключення виникне в деструкції, то або компілятор буде змушений видалити не повністю звільнений об'єкт, або об'єкт залишиться існуючим, тобто виникне витік пам'яті. Внаслідок цього генерація неперехвативаемих винятків у деструкторів в ряді випадків просто забороняється.

Джоел Спольскі вважає, що код, розрахований на роботу з винятками, втрачає лінійність та передбачуваність. Якщо в класичному коді виходи з блоку, процедури або функції знаходяться тільки там, де їх явно вказав програміст, то в коді з винятками виключення (потенційно) може відбутися в будь-якому операторі та аналізом самого коду неможливо дізнатися, де саме виключення можуть відбуватися. У коді ж, розрахованому на виключення, передбачити, в якому місці відбудеться вихід з блоку коду, неможливо, і будь-який оператор повинен розглядатися як потенційно останній в блоці, в результаті складність коду зростає, а надійність знижується. [1]

Також в складних програмах виникають великі "нагромадження" операторів try ... finally try ... finally і try ... catch try ... catch ( try ... except), якщо не використовувати аспекти.


5. Перевіряються виключення

5.1. Деякі проблеми простої обробки виключень

Спочатку (наприклад, в C + +), не існувало ніякої формальної дисципліни опису, генерації та обробки виключень: будь виняток може бути порушено в будь-якому місці програми, і, якщо для нього не знаходиться обробника в стеку викликів, виконання програми переривається аварійно. Якщо функція (особливо бібліотечна) генерує виключення, то для стійкої роботи використовує її програма повинна перехоплювати їх все. Коли з якоїсь причини одне з можливих винятків виявляється необробленим, буде відбуватися несподіване аварійне завершення програми.

З подібними ефектами можна боротися організаційними заходами, описуючи можливі виключення, що виникають в бібліотечних модулях, у відповідній документації. Але при цьому завжди залишається можливість пропустити необхідний обробник через випадкової помилки або невідповідності документації коду (що зовсім не рідкість). Щоб повністю виключити втрату обробки виключень, в оброблювачі доводиться спеціально додавати гілку обробки "всіх інших" винятків (яка гарантовано перехопить будь-які, навіть заздалегідь невідомі виключення), але такий вихід не завжди оптимальний. Більш того, приховування всіх можливих виключень може призвести до ситуації, коли будуть приховані серйозні, і при цьому важко виявляються помилки.


5.2. Механізм перевіряються винятків

Пізніше в ряді мов, наприклад, в 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.


5.3. Переваги та недоліки

Перевіряються винятку знижують кількість ситуацій, коли виключення, яке могло бути оброблено, викликало критичну помилку в програмі, оскільки за наявністю обробників стежить компілятор. Це особливо корисно при змінах коду, коли метод, який не міг раніше викидати виключення типу X, починає це робити; компілятор автоматично відстежить всі випадки його використання і перевірить наявність відповідних обробників. Наприклад, якщо при зміні формули обчислень в методі з'явилася раніше було у ньому операція ділення, буде автоматично перевірено наявність обробника виключення "розподіл на нуль".

Іншим корисним якістю перевіряються винятків є те, що вони сприяють осмисленого написання обробників: програміст явно бачить повний і правильний список винятків, які можуть виникнути в даному місці програми, і може написати на кожне з них осмислений обробник замість того, щоб створювати "на всяк випадок "загальний обробник всіх винятків, однаково реагує на всі позаштатні ситуації.

У перевіряються винятків є й недоліки.

  • Вони змушують створювати обробники винятків, з якими програміст в принципі впоратися не може, наприклад помилок введення-виведення в веб-додатку. Це призводить до появи "дурних" обробників, які не роблять нічого або дублюють системний обробник критичної помилки (наприклад, виводять стек виклику виключення) і, в підсумку, тільки засмічують код.
  • Стає неможливим додавання нового перевіряється виключення в метод, описаний в бібліотеці, оскільки це порушує зворотну сумісність. (Це вірно і для небібліотечних методів, але в цьому випадку проблема менш істотна, оскільки весь код, в остаточному підсумку, доступний і може бути перероблений).

Через перелічених недоліків при обов'язковості використання перевіряються винятків цей механізм часто обходять. Наприклад, багато бібліотек оголошують всі методи як викидають деякий суперклас винятків (наприклад, Exception), і тільки на цей тип виключення створюються оброблювачі. Результатом стає те, що компілятор змушує писати обробники винятків навіть там, де вони об'єктивно не потрібні. Більш правильним підходом вважається перехоплення всередині методу нових винятків, породжених викликуваним кодом, а при необхідності передати виключення далі - "загортання" його в виняток, вже повертане методом. Наприклад, якщо метод змінили так, що він починає звертатися до бази даних замість файлової системи, то він може сам ловити SQLException і викидати замість нього знову створюваний IOException, вказуючи в якості причини вихідне виняток. Зазвичай рекомендується спочатку оголошувати саме ті винятки, які доведеться обробляти зухвалому коду. Скажімо, якщо метод витягує вхідні дані, то для нього доцільно оголосити IOException, а якщо він оперує SQL-запитами, то, незалежно від природи помилки, він повинен оголошувати SQLException. У будь-якому випадку, набір викидаються методом виключень повинен ретельно продумуватися. При необхідності має сенс створювати власні класи виключень, наслідуючи їх від Exception або інших підходящих перевіряються винятків.


5.4. Винятки, що не потребують перевірки

Неможливо зробити перевіряються взагалі всі винятки, так як деякі виняткові ситуації по своїй природі такі, що їх виникнення можливе в будь-якому або майже будь-якому місці програми, а обробити їх програміст не в змозі. В основному це виключення, що відносяться до одного з двох видів:

  • Винятки, що виникають у зовнішньому по відношенню до програми середовищі з причин, які можуть бути не пов'язані з виконанням програми. Прикладом такої ситуації може бути помилка середовища виконання програми на Java. Вона потенційно можлива при виконанні будь-якої команди, то є відповідна виключення довелося б оголошувати в будь-якого методу; за рідкісними винятками в прикладній програмі не може бути осмисленого обробника подібної помилки - адже якщо середа виконання працює невірно, на що вказує сам факт виключення, немає ніякої гарантії , що і обробник буде виконаний правильно.
  • Винятки часу виконання, зазвичай пов'язані з помилками програміста. Такі винятки виникають через логічних помилок розробника або недостатності перевірок в коді. Наприклад, помилка звернення по неініціалізувати (нульового) покажчику, як правило, означає, що програміст або пропустив десь ініціалізацію змінної, або при виділенні динамічної пам'яті не перевірив, чи дійсно пам'ять була виділена. Як перше, так і друге вимагає виправлення коду програми, а не створення обробників.

Виносити подібні помилки взагалі за межі системи обробки виключень нелогічно і незручно, хоча б тому, що іноді вони все-таки перехоплюються і обробляються. Тому в системах з перевіряються винятками частина типів виключень виводиться з-під механізму перевірки і працює традиційним чином. У Java це класи виключень, успадковані від java.lang.Error - фатальні помилки середовища виконання і java.lang.RuntimeException - помилки часу виконання, як правило, пов'язані з помилками кодування або недостатністю перевірок в коді програми (невірний аргумент, звернення по порожній посиланню , вихід за межі масиву, невірне стан монітора і т. п.).


Примітки

  1. 13 - Joel on Software - www.joelonsoftware.com/items/2003/10/13.html