Винятки
У математиці Вам казали, що ділити на нуль не можна — будь-яке таке ділення буде помилкою. У 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;
Деякі типи винятків
NullPointerException
— доступ до null-об’єктаArrayIndexOutOfBoundsException
— доступ до неіснуючого індексу масивуArithmeticException
— арифметична помилкаIOException
— помилки виведення/введенняIllegalStateException
— некоректний аргументUnsupportedOperationException
— неможлива операція (дія)