Винятки

У математиці Вам казали, що ділити на нуль не можна — будь-яке таке ділення буде помилкою. У Java є механізм “кидання” деяких об’єктів, з яким Ви сьогодні познайомитесь. Об’єкти таких класів мають наслідувати клас Throwable (“той, що можна кинути”). Найчастіше використовуються два класи та їх підкласи: Error (Помилки) та Exception (Винятки). Перші є зазвичай системними, “справжніми” помилками, а останні використовують для неоднозначних або неочікуванних ситуацій. Наприклад, ми пропонуємо користувачу ввести число n й ділимо на нього, але ми не можемо знати, яке саме число:

System.out.println( 2 / n );

У випадку, якщо користувач введе нуль, то Java повідомить про виняткову ситуацію — “кине” виняток ArithmeticException (Арифметичний виняток). Не завжди можливо просто перевірити умову через if перед дією, тому є механізм уловлювання винятків (або помилок також) за допомогою try-catch. Загальна схема:

try {
    //Код, який може викликати виняток (не спрацювати)
} catch (Тип_виключення змінна_виключення){
    //Код, який буде виконаний у випадку "спіймання" виключення
} finally {
    //Код, що виконається у будь-якому випадку
}

finally не є обов’язковим, про нього пізніше. Таким чином, можна записати це ділення з перевіркою на винятки так:

try {
    System.out.println( 2 / n );
} catch (ArithmeticException e){
    System.err.println("Ділити на нуль не можна!");
    e.printStackTrace();
}

Тут, окрім виведення в потік stderr (для помилок), використовується метод самого виключення printStackTrace(), який виводить також інформацію про місце в програмі, де було викликане виключення.

finally

У наступній темі будемо працювати з файлами, а поки я буду писати псевдокодом для простішого розуміння. У деяких випадках, з винятком або без, програма може закінчити роботу або просто пропустити частину коду. Так може траплятися із файлами, які можуть залишитись відкритими у Java, що може спричинити їх пошкодження. Для того, щоб цьому запобігти, є блок finally — він виконається завжди (у 99% випадків), не зважаючи на винятки. Для прикладу, ми відкриваємо файл, а потім намагаємося (try) записати щось в нього (адже це не завжди може вийти: відсутність дозволу на запис, недостатньо місця на диску тощо) і у будь-якому випадку закриваємо цей файл:

File f = відкритиФайл();
try {
	f.записати("Текст");
} catch (Exception e) {
	System.err.println("Помилка запису до файлу.");
} finally {
	f.закрити();
}

try-з-ресурсами

У версії Java (1.)7 з’явилась спрощена версія try-catch-finally, у якій можна написати в дужках біля try “ресурс”, з яким ми будемо працювати (у випадку вище це відкриття файлу), і тоді не потрібно писати finally з його закриттям:

try (File f = відкритиФайл()) {
	f.записати("Текст");
} catch (Exception e) {
	System.err.println("Помилка запису до файлу.");
}

Кидання

Інколи потрібно самому викликати виняток (навіть власний). Так як винятки є об’єктами, достатньо створити новий об’єкт (наприклад, класу Exception) і кинути його слово throw:

throw new Exception("Виникла помилка!");

Зазначу, що потрібно також попередити Java, що функція, у якій Ви кидаєте цей виняток, може таке зробити — після аргументів у дужках треба вказати, що функція throws певні типи винятків через кому (або просто загальний тип Exception):

int division(int a, int b) throws ArithmeticException, NullPointerException {
	...
}

Створення нових винятків

Створити власний вид винятку можна просто успадковуванням класу Exception з перезаписуванням конструкторів (одного або більше), найчастіше просто викликають конструктор суперкласу через super():

public class MyCoolException extends Exception {
	public MyCoolException(String msg) {
		super(msg);
	}
	public MyCoolException(String msg, Throwable cause) {
		super(msg, cause);
	}
}

Кидати такий виняток можна так само як і будь-який інший:

throw new MyCoolException("Мій класний виняток!");

null

Спеціальний тип даних, про який я раніше не згадував це null. Практично, він являє собою нічого і вказує на те, що такий об’єкт не існує, майже як пуста множина у математиці. Його можна задавати об’єктом вручну, або інколи Java сама задає цей тип об’єктам. Майже будь-що може бути “порожнім” або “неіснуючим”, окрім примітивних типів даних (таких як int, boolean). У випадку, якщо спробувати зробити будь-яку дію з таким нульовим об’єктом, буде виключення NullPointerException.

Integer a = null;
File b = null;
String[] c = null;

Різниця між 0 та null

Деякі типи винятків

  • NullPointerException — доступ до null-об’єкта
  • ArrayIndexOutOfBoundsException — доступ до неіснуючого індексу масиву
  • ArithmeticException — арифметична помилка
  • IOException — помилки виведення/введення
  • IllegalStateException — некоректний аргумент
  • UnsupportedOperationException — неможлива операція (дія)

Copyleft 🄯 2020–2024 Михайло Стецюк <yaBobJonez@gmail.com>.
Сайт має ліцензію Creative Commons License.
Дякую рідній школі та вчителям!