- Объяснять, что такое исключение, и читать трассировку стека
- Использовать блоки
try,catchиfinally - Различать проверяемые и непроверяемые исключения и писать собственный класс исключения
Пользователь ввёл «abc» вместо возраста, файл удалён, пропал интернет — в реальных программах не всё идёт по плану. Хорошая программа в таких случаях не «падает», а вежливо сообщает о проблеме и продолжает работу. В Java неожиданные ситуации обрабатывают с помощью исключений (exceptions).
Что такое исключение?
Исключение — это объект, описывающий событие, которое нарушает нормальный ход программы. Когда оно возникает, Java его «выбрасывает» (throw): текущий метод сразу останавливается, и исключение поднимается по цепочке вызовов, пока его кто-нибудь не перехватит. Если никто не перехватит, программа остановится и выведет в консоль трассировку стека (stack trace).
public class Main {
public static void main(String[] args) {
int[] marks = {5, 4, 3};
System.out.println("Start");
System.out.println(marks[5]);
System.out.println("End");
}
}Start Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3 at Main.main(Main.java:5)
Читай трассировку сверху вниз: сначала тип исключения (ArrayIndexOutOfBoundsException), затем сообщение (индекс 5 выходит за границы массива длиной 3), а потом место — 5-я строка файла Main.java. «End» не напечаталось: после исключения остаток метода не выполняется.
try, catch и finally
Опасный код помещают в блок try. Если возникает исключение, управление переходит в блок catch подходящего типа. Блок finally выполняется в любом случае — было исключение или нет; в нём обычно делают «уборку»: закрывают файл или соединение.
public class Main {
public static void main(String[] args) {
String[] inputs = {"42", "abc", "0"};
for (String input : inputs) {
try {
int n = Integer.parseInt(input);
System.out.println("100 / " + n + " = " + (100 / n));
} catch (NumberFormatException e) {
System.out.println("Not a number: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("Math error: " + e.getMessage());
} finally {
System.out.println("-- checked \"" + input + "\"");
}
}
}
}100 / 42 = 2 -- checked "42" Not a number: For input string: "abc" -- checked "abc" Math error: / by zero -- checked "0"
Integer.parseInt("abc")не может превратить текст в число и выбрасываетNumberFormatException.- Деление целого числа на ноль вызывает
ArithmeticException. (Любопытно, что100.0 / 0не выбрасывает исключение, а даётInfinity.) e.getMessage()возвращает сообщение исключения. После исключения программа не остановилась — цикл продолжился со следующим значением.finallyсработал во всех трёх случаях.
Проверяемые и непроверяемые исключения
Общий родитель всех исключений — Throwable. От него происходят Error (серьёзные проблемы JVM, например нехватка памяти, — их обычно не перехватывают) и Exception. У Exception есть особая ветвь — RuntimeException. Это деление задаёт уникальное правило Java:
| Признак | Проверяемые (checked) | Непроверяемые (unchecked) |
|---|---|---|
| Наследуется от | Exception (но не RuntimeException) | RuntimeException |
| Требует ли компилятор? | да: перехвати или объяви через throws | нет |
| Обычно означает | проблема вне контроля программы | ошибка программиста |
| Примеры | IOException, FileNotFoundException | NullPointerException, ArithmeticException, IllegalArgumentException |
Например, если написать new FileReader("data.txt") без try, код не скомпилируется: unreported exception FileNotFoundException; must be caught or declared to be thrown. Компилятор словно говорит: «Файла может не оказаться — заранее реши, что делать в этом случае».
throw, throws и собственные исключения
Исключение можно выбросить и самому: throw new IllegalArgumentException("..."). Это лучший способ не дать методу принять неверные данные. Чтобы создать свой класс исключения, унаследуй его от Exception (проверяемое) или RuntimeException (непроверяемое). Метод, выбрасывающий проверяемое исключение, должен объявить это в заголовке через throws.
public class Main {
static void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("Invalid age: " + age);
}
System.out.println("Age set to " + age);
}
public static void main(String[] args) {
try {
setAge(25);
setAge(-3);
setAge(40);
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
System.out.println("Program continues");
}
}Age set to 25 Error: Invalid age: -3 Program continues
setAge(40) так и не был вызван: как только setAge(-3) выбросил исключение, блок try прервался и управление перешло в catch. А теперь создадим собственное проверяемое исключение — для случая, когда в кошельке не хватает денег:
public class Main {
public static void main(String[] args) {
Wallet wallet = new Wallet(30);
try {
wallet.pay(12);
wallet.pay(25);
} catch (InsufficientFundsException e) {
System.out.println(e.getMessage());
System.out.println("Missing: " + e.getMissing() + " AZN");
}
}
}
class InsufficientFundsException extends Exception {
private final double missing;
InsufficientFundsException(double missing) {
super("Not enough money in the wallet");
this.missing = missing;
}
double getMissing() { return missing; }
}
class Wallet {
private double balance;
Wallet(double balance) { this.balance = balance; }
void pay(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
System.out.println("Paid " + amount + ", left " + balance);
}
}Paid 12.0, left 18.0 Not enough money in the wallet Missing: 7.0 AZN
Главное
- Исключение — событие, нарушающее нормальный ход программы; если его не перехватить, программа остановится и выведет трассировку стека.
tryсодержит опасный код,catchперехватывает исключение определённого типа, аfinallyвыполняется всегда.- Проверяемые исключения (
IOException) нужно перехватить или объявить черезthrows; наследникиRuntimeExceptionне проверяются. throw new ...выбрасывает исключение; для собственного исключения наследуйся отExceptionилиRuntimeException.- Не пиши пустой блок
catch— информация об ошибке теряется.
Проверь себя
Вопросов: 10. Каждый правильный ответ приносит XP.
finally?