JavaRush /Курси /C# SELF /Знайомство з винятками та їхньою ієрархією

Знайомство з винятками та їхньою ієрархією

C# SELF
Рівень 13 , Лекція 0
Відкрита

1. Вступ

Уявіть, що ви пишете калькулятор для ділення двох чисел. Усе працює чудово, поки хтось не вирішить поділити на нуль:

int a = 10;
int b = 0;
int result = a / b; // Бум!
Ділення на нуль спричиняє виняток

У цей момент програма «падає», і користувач бачить лякаюче повідомлення про помилку. Це й є виняткова ситуація — подія, що не повинна траплятися в «нормальному» сценарії роботи програми й потребує особливої уваги.

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

Коли трапляється помилка виконання (наприклад, ділення на нуль, спроба звернення до відсутнього файлу або — старий знайомий — розіменування null), .NET «викидає» (throw) спеціальний об’єкт‑виняток. Далі розпочинається пошук обробника, який зможе «перехопити» (catch) ситуацію й знає, як відреагувати.

Чому не повертати «код помилки»?

Можна було б повертати код помилки — і багато давніх мов (Pascal, C, та й деякі сучасні API) так роблять. Але це незручно й небезпечно: легко забути перевірити код помилки (бо усі сподіваються на краще) — і дуже складно зрозуміти, де саме все пішло не так. Винятки дають змогу централізовано відстежувати будь‑які помилки й реагувати на них гнучко, не захаращуючи основний код купою перевірок.

2. Генерування винятку

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


int[] arr = new int[2];
arr[10] = 5; // виняток буде згенеровано автоматично: System.IndexOutOfRangeException

throw new Exception("Абсолютна катастрофа!"); // вручну генеруємо виняток Exception

Навіть якщо вам здається, що ваша програма ідеально спроєктована, завжди може трапитися щось неочікуване: користувач закрив файл, інтернет зник, хтось вимкнув живлення комп’ютера (ну майже).

На щастя, .NET надає не лише механізм генерування винятків, а й засоби для їхнього перехоплення та обробки — ними ми займемося трохи пізніше.

3. Життєвий цикл винятку: від throw до catch

Коли в коді трапляється щось неприємне, .NET запускає «екстрену процедуру»:

  1. Створює об’єкт винятку (наприклад, IndexOutOfRangeException).
  2. Викидає його за допомогою ключового слова throw.
  3. Шукає обробник: переглядає стек викликів знизу вгору (від поточного методу до викликача) й шукає перший блок catch, який відповідає типу згенерованого винятку.
  4. Якщо знайдено обробник — програма продовжує виконання всередині блоку catch.
  5. Якщо жодного обробника не знайдено — програма аварійно завершується й виводить «стек викликів» з деталями помилки.

Це схоже на те, як м’яч котиться сходами: доки не трапиться «приймач», виняток «стрибає» вгору стеком.

4. Ієрархія винятків у .NET

Дерево «батьків і дітей»

У .NET (як і в більшості ООП‑мов) винятки реалізовано у вигляді класів, що успадковуються один від одного й утворюють ієрархію.

Усі вони мають спільного предка — базовий клас System.Exception.


System.Object
    └─ System.Exception
         ├─ System.SystemException
         │     ├─ System.NullReferenceException
         │     ├─ System.IndexOutOfRangeException
         │     ├─ System.DivideByZeroException
         │     ├─ System.OutOfMemoryException
         │     └─ ... і багато інших
         ├─ System.IO.IOException
         │     ├─ System.IO.FileNotFoundException
         │     ├─ System.IO.DirectoryNotFoundException
         │     └─ ...
         ├─ System.ArgumentException
         │     ├─ System.ArgumentNullException
         │     └─ System.ArgumentOutOfRangeException
         └─ (твої власні Exception-класи)
Схематична ієрархія винятків у .NET

Чому класи?

Завдяки ієрархії класів можна перехопити одразу цілу «сім’ю» проблем — наприклад, усі помилки, пов’язані з аргументами методів (ArgumentException та його нащадки). Ба більше, це дає змогу додавати власні типи винятків (про це — на наступних лекціях).

Найпоширеніші винятки .NET

  • NullReferenceException — спроба звернення до методу або властивості об’єкта, який дорівнює null. Старий знайомий!
  • DivideByZeroException — ділення на нуль.
  • IndexOutOfRangeException — вихід за межі масиву.
  • ArgumentException, ArgumentNullException, ArgumentOutOfRangeException — некоректні аргументи методів.
  • FileNotFoundException, IOException — проблеми під час роботи з файлами.
  • InvalidOperationException — операція неможлива у поточному стані об’єкта.
  • FormatException — некоректний формат даних (наприклад, спроба перетворити "abcd" у число).

5. Приклади: як виникають різні винятки

Розгляньмо для наочності приклади коду, що спричиняють різні винятки.

Приклад 1: NullReferenceException

string? str = null;
Console.WriteLine(str.Length); // Тут «Бум!» — str дорівнює null

Вивід:

Unhandled exception. System.NullReferenceException: Object reference not set to an instance of an object.

Приклад 2: DivideByZeroException

int a = 42;
int b = 0;
int c = a / b; // Небезпечно! Ділення на 0

Вивід:

Unhandled exception. System.DivideByZeroException: Attempted to divide by zero.

Приклад 3: IndexOutOfRangeException

int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[5]); // Немає елемента з індексом 5

Тут явне звернення за межі масиву, і вивід такий:

Unhandled exception. System.IndexOutOfRangeException: Index was outside the bounds of the array.

Приклад 4: FileNotFoundException

using System.IO;

string content = File.ReadAllText("secret.txt");

Якщо у вас немає файлу з назвою "secret.txt", то отримаєте приблизно таке повідомлення:

Unhandled exception. System.IO.FileNotFoundException: Could not find file '/Users/zapp/RiderProjects/ConsoleApp1/ConsoleApp1/bin/Debug/net9.0/secret.txt'.

Приклад 5: FormatException

string input = "trinadtsyat";
int number = int.Parse(input); // Рядок не число

Вивід:

Unhandled exception. System.FormatException: The input string 'trinadtsyat' was not in a correct format.

6. Як використовувати отримані знання?

Розуміння того, як працюють винятки, дуже важливе для будь‑якого розробника. Це не просто «теорія заради теорії», а практична навичка, що безпосередньо впливає на стабільність ваших програм. Коли ви знаєте, як правильно обробляти помилки, програма не «падатиме» при першому ж збої, а натомість спокійно й зрозуміло повідомить користувача, що пішло не так. Це робить її надійнішою, професійнішою і просто дружнішою до людей.

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

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

7. Типові помилки під час роботи з винятками

Помилка № 1: ігнорування винятків як таких.
Деякі новачки (а іноді й досвідчені розробники) сприймають винятки як щось шкідливе або таке, що заважає. Вони або повністю ігнорують їх, або, що ще гірше, обгортають код у catch { } і нічого не роблять. У результаті програма «мовчки» продовжує роботу в дивному стані, і відстежити причину збою стає неможливо.

Помилка № 2: плутанина між винятками й звичайними помилками.
Часто забувають, що не кожну помилку треба ловити через try-catch. Наприклад, якщо користувач увів некоректні дані, краще спочатку перевірити їх вручну, а не сподіватися на FormatException і тим більше не використовувати винятки як механізм керування логікою. Винятки — це про виняткові випадки, а не про рутину.

Помилка № 3: неправильне розуміння ієрархії винятків.
Іноді намагаються перехоплювати занадто загальний клас (Exception) і в результаті ловлять усе підряд, включно з тими помилками, які краще не обробляти. А іноді навпаки — ловлять занадто вузькі типи (IndexOutOfRangeException, NullReferenceException), забуваючи, що можуть виникнути й інші. Важливо розуміти, як улаштована ієрархія винятків у .NET і що саме ви хочете обробляти.

І головне — пам’ятайте: винятки в C# — це не аварія і не сигнал «усе пропало», а просто механізм перемикання на особливий сценарій виконання. Це потужний інструмент, якщо користуватися ним правильно.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ