Обробка винятків

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Обро́бка ви́нятків (також опрацьо́вування (обробля́ння) винятко́вих ситуа́цій[1], англ. exception handling) — механізм мов програмування, призначений для обробки помилок часу виконання й інших можливих проблем (винятків), які можуть виникнути під час виконання програми.

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

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

[ред. | ред. код]

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

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

Основний недолік винятків — у їхній невисокій швидкості. У місцях програми, критичних за швидкістю, не варто порушувати й обробляти винятки.

У складних програмах виникають великі «нагромадження» операторів try … finally і try … catch (try … except), але без застосування механізму обробки винятків аналогічна за функціональністю програма виглядала б ще більше захаращеною.

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

[ред. | ред. код]

Більшість сучасних мов програмування, таких як ActionScript, Ada, C++, Common Lisp, D, Object Pascal, Eiffel, Java, JavaScript, Objective-C, Objective Caml, Ruby, PHP (з версії 5), Python, SML, Глагол, всі мови платформи .NET тощо, мають вбудовану підтримку обробки винятків. У цих мовах, під час виникнення виняткової ситуації (точніше, винятку, підтримуваного мовою), відбувається розкручування стека викликів до першого обробника винятків відповідного типу, і керування передається обробникові.

За винятком незначних відмінностей у синтаксисі, існує лише пара варіантів обробки винятків. У найпоширенішому з них виняткова ситуація генерується спеціальним оператором (throw або raise) з об'єктом-винятком. Водночас конструювання такого об'єкта само собою викиду винятку не спричиняє. Область дії обробників починається спеціальним ключовим словом 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("Програма завершена");
}

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

У деяких мовах, наприклад Сі або Perl, немає вбудованої обробки винятків.

Винятки, що перевіряються

[ред. | ред. код]

Спочатку (наприклад, у C++), винятки не були обов'язковими для обробки. Якщо якийсь виняток не обробляється, тобто якщо для нього немає обробника в стеку виклику, або обробник викинув виняток наново, то виконання програми уривається.

У новіших мовах, наприклад у Java, разом з «класичними» з'явилися винятки, що перевіряються. Обробка таких винятків перевіряється компілятором. Метод, у якому може виникнути виняток (зокрема й у методах, що викликаються) зобов'язаний або обробити його, або оголосити, що може викинути[куди?] такий виняток.

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

[ред. | ред. код]

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

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

У результаті, багато бібліотек оголошують усі методи як такі, що викидають деякий суперклас винятків (наприклад, Exception). У результаті, компілятор «примушує» писати обробники винятків навіть там, де вони, здавалося б, не потрібні.

Примітки

[ред. | ред. код]
  1. О. Кочерга, Є. Мейнарович, Англійсько-українсько-англійський словник наукової мови (фізика та споріднені науки). Частина І англійсько-українська 2010р.

Див. також

[ред. | ред. код]