Что такое исключения
Исключение (exception) — это объект, которым Java сообщает, что что-то пошло не так: деление на ноль, обращение за границу массива, отсутствующий файл. Когда исключение возникает, обычный ход программы прерывается. Если его никто не обработает, программа завершится и выведет описание ошибки.
Первое исключение
Поделим целое число на ноль:
void main() {
int apples = 10;
int people = 0;
IO.println("Начинаем делить");
IO.println(apples / people);
IO.println("Эта строка не выполнится");
}Результат:
Начинаем делить
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:6)Первая строка успела вывестись, а после ошибки программа остановилась. Говорят, что код выбросил исключение (throw).
Как читать сообщение
Сообщение об исключении состоит из трёх частей:
java.lang.ArithmeticException— тип исключения, то есть его класс. По нему сразу понятно, что за ошибка./ by zero— сообщение с подробностями.at Main.main(Main.java:6)— трассировка стека (stack trace): где именно возникла ошибка. Здесь — в методеmain, строка 6.
Если ошибка случилась глубоко внутри вызовов, строк at будет несколько. Самая верхняя — место, где исключение возникло, ниже — кто вызвал этот код.
int divide(int a, int b) {
return a / b;
}
void main() {
IO.println(divide(10, 0));
}Результат:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.divide(Main.java:2)
at Main.main(Main.java:6)Частые исключения
С этими исключениями новички сталкиваются чаще всего:
| Исключение | Когда возникает |
|---|---|
ArithmeticException | целочисленное деление на ноль |
ArrayIndexOutOfBoundsException | индекс за пределами массива |
NullPointerException | вызов метода у null |
NumberFormatException | строку не удалось превратить в число |
IllegalArgumentException | методу передали недопустимый аргумент |
Например, Integer.parseInt не поймёт буквы:
void main() {
int age = Integer.parseInt("двадцать");
}Результат:
Exception in thread "main" java.lang.NumberFormatException: For input string: "двадцать"
at Main.main(Main.java:2)Иерархия исключений
Все исключения — объекты классов, унаследованных от Throwable. У него две ветви:
Error— серьёзные сбои самой виртуальной машины, например нехватка памяти (OutOfMemoryError). Их обычно не обрабатывают. Откуда берутся такие сбои, рассказано в уроке Память и сборка мусора.Exception— ошибки, с которыми программа может справиться. Его подклассRuntimeExceptionобъединяет ошибки в логике кода: деление на ноль,null, неверный индекс.
Как это деление влияет на код, разберём в уроке о проверяемых и непроверяемых исключениях.
Исключение — тоже объект
Раз исключение — объект, у него есть методы. getMessage() возвращает сообщение, а getClass().getSimpleName() — короткое имя класса. Чтобы получить объект исключения, его нужно перехватить конструкцией try-catch — ей посвящён следующий урок:
void main() {
try {
int[] scores = {5, 4, 3};
IO.println(scores[3]);
} catch (ArrayIndexOutOfBoundsException e) {
IO.println(e.getClass().getSimpleName());
IO.println(e.getMessage());
}
}Результат:
ArrayIndexOutOfBoundsException
Index 3 out of bounds for length 3Частая ошибка
Самое частое исключение в Java — NullPointerException: метод вызывают у значения null, то есть у «ничего». Например, метод вернул null, а результат сразу использовали:
String findName() {
return null;
}
void main() {
IO.println(findName().length());
}Результат:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.length()" because the return value of "Main.findName()" is null
at Main.main(Main.java:6)Современная Java подробно объясняет, что именно оказалось null: здесь — результат метода findName(). Прежде чем вызывать методы у значения, которое может отсутствовать, проверяйте его (if (name != null)) или возвращайте из метода Optional.