Мова програмування Java використовує винятки, щоб обробляти помилки та інші виняткові події.
Виняток - це подія, що виникає під час виконання програми й порушує нормальний потік інструкцій. У Java винятки виникають явно, і цю дію називають киданням винятку. А дію з обробки винятку називають перехопленням винятку.
У Java всі винятки є підкласами класу Exception, який, своєю чергою, є підкласом Throwable.
Java розрізняє два типи винятків:
Перевірювані винятки - це виняткові умови, які застосунок має передбачати й уміти з них відновлюватися.
Приклад перевірюваного винятку - FileNotFoundException, який виникає, коли метод намагається прочитати файл, якого не існує.
Цей тип винятків перевіряється під час компіляції: методи, які кидають перевірювані винятки, мають зазначити це у своїй сигнатурі, а код, що викликає метод, який може кинути перевірюваний виняток, зобовʼязаний його обробити, інакше код не скомпілюється.
Усі перевірювані винятки - це підкласи Exception, які не розширюють RuntimeException.
Неперевірювані винятки - це виняткові умови, які застосунок зазвичай не може передбачити й не може з них відновитися.
Приклад неперевірюваного винятку - NullPointerException, який виникає, коли метод, що має прийняти значення, відмінне від null, натомість отримує null.
Цей тип винятків не перевіряється під час компіляції: методи, які кидають неперевірювані винятки, не зобовʼязані зазначати це у своїй сигнатурі, а код, що викликає метод, який може кинути неперевірюваний виняток, не зобовʼязаний його обробляти.
Усі неперевірювані винятки успадковують RuntimeException, який, своєю чергою, розширює Exception.
Метод у Java може кинути виняток за допомогою інструкції throw.
Коли метод кидає перевірюваний виняток, це потрібно зазначити в сигнатурі методу за допомогою ключового слова throws, як показано в прикладі нижче.
Це змушує код, який викликає метод, передбачити можливість виникнення винятку й належно його обробити.
public class InsufficientBalanceException extends Exception {
}
public class BankAccount {
public void withdraw(double amount) throws InsufficientBalanceException {
if (balance < amount) {
throw new InsufficientBalanceException();
}
// rest of the method implementation
}
}
Коли метод кидає неперевірюваний виняток, зазначати це в сигнатурі методу не обовʼязково, хоч це й підтримується.
public class BankAccount {
public void withdraw(double amount) {
if (amount < 0) {
throw new IllegalArgumentException("Cannot withdraw a negative amount");
}
// rest of the method implementation
}
}
В Java винятки обробляють за допомогою ключових слів try, catch і finally.
try.try іде один або кілька блоків catch, які перехоплюють винятки, кинуті в блоці try.catch може йти блок finally, який завжди виконується після блоку try, незалежно від того, чи було кинуто виняток.У наступному прикладі показано, як працюють ці ключові слова:
public class ATM {
public void withdraw(BankAccount bankAccount, double amount) {
try {
System.out.println("Withdrawing " + amount);
bankAccount.withdraw(amount);
System.out.println("Withdrawal succeeded");
} catch (InsufficientBalanceException) {
System.out.println("Withdrawal failed: insufficient balance");
} catch (RuntimeException e) {
System.out.println("Withdrawal failed: " + e.getMessage());
} finally {
System.out.println("Current balance: " + bankAccount.getBalance());
}
}
}
У цьому прикладі, коли винятку не кинуто, виводиться таке:
Withdrawing 10.0
Withdrawal succeeded
Current balance: 5.0
Якщо ж інструкція bankAccount.withdraw(amount) кине InsufficientBalanceException, виводиться таке:
Withdrawing 10.0
Withdrawal failed: insufficient balance
Current balance: 5.0
Або, якщо неперевірюваний виняток кине bankAccount.withdraw(amount), виводиться таке:
Withdrawing -10.0
Withdrawal failed: Cannot withdraw a negative amount
Current balance: 5.0
У Java є також окрема категорія, яку називають помилками: це серйозні проблеми, зовнішні щодо застосунку.
Приклад помилки - OutOfMemoryError, який виникає, коли застосунок намагається використати більше памʼяті, ніж є в системі.
Як і неперевірювані винятки, помилки не перевіряються під час компіляції. Різниця в тому, що вони означають проблеми на рівні системи, і зазвичай їх кидає віртуальна машина Java або середовище, а не застосунок. Застосунки зазвичай не повинні намагатися їх перехоплювати чи обробляти.
Усі помилки в Java успадковують клас Error.
Як уже зазначалося, винятки - це події, що порушують нормальний потік інструкцій, і призначені вони для обробки виняткових подій. Тому не рекомендується використовувати винятки для керування потоком виконання у своєму застосунку.