Exception (виняток) – це об’єкт, який повідомляє про помилку або непередбачену ситуацію, що виникла під час виконання програми та порушила її нормальний перебіг.
Що таке обробка винятків
Exception handling (обробка винятків) – це механізм, який дозволяє вказати програмі, що робити якщо під час виконання виникла помилка або непередбачена ситуація. Наприклад, коли програма не може знайти файл (FileNotFoundException) або підключитися до бази даних (SQLException), і такі помилки не оброблені, програма зупиниться. Якщо ж використати конструкцію try-catch, програма зможе перехопити виняток, обробити його та продовжити роботу.
Різниця між Error та Exception
Error – це серйозна помилка, яка виникає під час роботи Java і зазвичай не може бути виправлена програмою. Вона вказує на збої у роботі самої віртуальної машини Java (JVM) або системного середовища, наприклад: OutOfMemoryError, StackOverflowError. Такі помилки не призначені для обробки в коді – програма не повинна намагатися їх перехоплювати за допомогою try-catch, оскільки відновлення після них зазвичай неможливе.
Exception – це виняткова ситуація, що виникає під час виконання програми та може бути оброблена в коді за допомогою конструкцій try-catch. Серед поширених прикладів – IOException (проблеми з читанням або записом файлів) та SQLException (помилки під час роботи з базами даних). Такі ситуації менш критичні, ніж Error, і зазвичай можуть бути передбачені та оброблені програмою.
Типи винятків у Java
Checked Exceptions – це тип винятків у Java, які успадковують клас Exception, але не є нащадками RuntimeException. Такі винятки називають перевіреними, тому що компілятор вимагає обов’язково обробити їх у коді через конструкцію try-catch або оголосити в сигнатурі методу за допомогою ключового слова throws. Приклади перевірених винятків: IOException, SQLException. Вони дозволяють виявляти потенційні помилки ще на етапі компіляції, що підвищує надійність програми.
Unchecked Exceptions – це винятки в Java, які успадковують клас RuntimeException. Серед них такі класи як ArithmeticException, NullPointerException, ArrayIndexOutOfBoundsException, тощо. Неперевірені винятки не вимагають обов’язкової обробки під час компіляції: компілятор не змушує використовувати конструкцію try-catch або оголошувати їх у сигнатурі методу через throws. Проте вони можуть виникати під час виконання програми, якщо не передбачити відповідні перевірки у коді.
Докладніше про Checked та Unchecked Exceptions.
Ключові слова Java при роботі з винятками
try – ключове слово, яке використовується для визначення блоку коду, в якому може виникнути виняток. Після блоку try обов’язково має йти хоча б один із блоків: catch, finally або обидва. Інакше кажучи, блок try не може існувати самостійно без супровідних блоків для обробки або завершальних дій.
catch – ключове слово, що використовується для обробки винятків, які виникли у відповідному блоці try. Блок catch завжди розташовується одразу після try і не може використовуватись самостійно. Після catch може бути блок finally, але його використання не є обов’язковим.
finally – використовується для визначення блоку коду, що виконується завжди, незалежно від того, чи виник виняток у блоці try, і чи був він оброблений у блоці catch. Блок finally гарантує виконання завершальних або необхідних дій, як наприклад закриття файлів або звільнення ресурсів.
throw – ключове слово в Java, яке дозволяє примусово згенерувати виняток у потрібному місці коду. Для цього з допомогою throw створюють об’єкт винятку – екземпляр класу, що наслідує Throwable (наприклад IllegalArgumentException, IOException, тощо). Оператор throw можна використовувати в будь-якому методі або блоці коду.
throws – використовується у сигнатурі методу для оголошення винятків, які цей метод може згенерувати під час виконання. Сам throws не створює винятки, а лише повідомляє код, що викликає метод, про можливість їх виникнення. Записується після списку параметрів методу і перед відкриваючою дужкою тіла методу.
Приклади обробки винятків у Java
Розглянемо приклади коду, що демонструють використання ключових слів Java для роботи з винятками:
1. try-catch-finally (обробка винятків):
public class Main {
public static void main(String[] args) {
try {
// Код, де може виникнути помилка
int result = 10 / 0; // ArithmeticException: / by zero
System.out.println("Результат: " + result);
}
catch (ArithmeticException e) {
// Обробка конкретного винятку
System.out.println("Помилка: Ділення на нуль!");
}
finally {
// Виконується завжди
System.out.println("Блок finally: Цей код виконається в будь-якому випадку");
}
}
}
// Output:
// Помилка: Ділення на нуль!
// Блок finally: Цей код виконається в будь-якому випадку2. throw (примусова генерація винятку):
public class Main {
static void checkAge(int age) {
if (age < 18) {
// Генерація винятку вручну
throw new IllegalArgumentException("Вік менше 18 років!");
}
System.out.println("Доступ дозволено");
}
public static void main(String[] args) {
try {
checkAge(15); // Виклик методу з невалідним значенням
}
catch (IllegalArgumentException e) {
System.out.println("Виняток: " + e.getMessage());
}
}
}
// Output:
// Виняток: Вік менше 18 років!3. throws (оголошення винятків методу):
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class Main {
// Метод оголошує, що може кинути виняток IOException
public static void readFile(String filePath) throws IOException {
// try-with-resources забезпечує автоматичне закриття BufferedReader
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
// Автоматичне закриття reader після виходу з блоку try
}
public static void main(String[] args) {
try {
readFile("example.txt"); // Спроба прочитати файл
} catch (IOException e) {
System.out.println("Помилка при читанні файлу: " + e.getMessage());
}
}
}
// Output:
// Помилка при читанні файлу: example.txt (The system cannot find the file specified)4. Комбінація try-catch з кількома блоками catch:
public class Main {
public static void main(String[] args) {
try {
int[] numbers = new int[5];
numbers[10] = 30; // ArrayIndexOutOfBoundsException
System.out.println(numbers[10]);
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Помилка індексу масиву: " + e.getMessage());
}
catch (Exception e) {
System.out.println("Загальний виняток: " + e);
}
}
}
// Output:
// Помилка індексу масиву: Index 10 out of bounds for length 5На що слід звернути увагу:
1. try-catch-finally:
- try: блок для “небезпечного” коду
- catch: перехоплює конкретний тип винятку
- finally: виконується завжди (навіть якщо виняток не виник)
2. throw:
- використовується для примусової генерації винятку
- часто використовується з кастомними перевірками
3. throws:
- вказує в сигнатурі методу винятки які він може генерувати
- змушує код що викликає метод обробити цей виняток
4. Особливості:
- блок try вимагає додавання блоків або catch, або finally
- при використанні кількох блоків catch, їх слід розташовувати для обробки від більш специфічних винятків до загальних
- finally часто використовується для звільнення ресурсів (закриття файлів, тощо)