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

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

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

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

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

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

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

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

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

Підтримка в різних мовах[ред.ред. код]

Більшість сучасних мов програмування, таких як ActionScript, Ada, C++, Common Lisp, D, Delphi, Eiffel, Java, JavaScript, OBJECTIVE-C, OCaml, 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). У результаті, компілятор «примушує» писати обробники винятків навіть там, де вони, здавалося б, не потрібні.