🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!
Привет! В прошлом уроке мы познакомились с исключениями в языке Java и рассмотрели примеры работы с ними.
Типы исключений
Как мы уже говорили, в Java очень много исключений, почти 400! Но все они разделены на группы, так что запомнить их довольно просто. Вот как это выглядит:

Все исключения имеют общего предка в классе Throwable
.
Из него вытекают две основные группы: исключения(Exception ) и ошибки(Error ).
Error — это критическая ошибка времени выполнения, связанная с работой виртуальной машины Java. В большинстве случаев Error не нужно обрабатывать, так как она указывает на серьезные недостатки в коде.
Самые известные из них — StackOverflowError (это происходит, например, когда метод вызывает себя бесконечно) и OutOfMemoryError (это происходит, когда недостаточно памяти для создания новых объектов).
Как видите, в таких ситуациях обычно не нужно ничего делать во время выполнения: код просто написан неправильно и нуждается в доработке.
Exception — это, ну, исключение: исключительная, незапланированная ситуация, которая возникает во время работы программы.
Они не такие серьезные, как Error, но все равно требуют нашего внимания.
Все исключения делятся на 2 типа: проверенные и непроверенные.

Все проверяемые исключения являются производными от класса Exception
.
Что означает «проверено»?
Мы упоминали об этом в прошлом уроке:
“Поэтому компилятор Java знает наиболее распространенные исключения и ситуации, в которых они могут возникнуть”.
Например, он знает, что если код считывает данные из файла, то этого файла вполне может не существовать. И таких ситуаций (о которых он может сделать вывод) очень много.
Соответственно, компилятор заранее проверяет наш код на наличие этих потенциальных исключений. Если он их обнаружит, то не будет компилировать код до тех пор, пока мы их не обработаем или не отбросим.
Второй тип исключений – “непроверенные”. Они являются производными от класса RuntimeException
.
Чем они отличаются от проверяемых исключений? Похоже, что от RuntimeException
(который описывает исключения времени выполнения) происходит множество различных классов.
Разница в том, что компилятор не предвидит этих ошибок. Он как бы говорит: “Когда код был написан, я не нашел ничего подозрительного, но во время его выполнения что-то пошло не так. Очевидно, в коде есть ошибки!”.
И это действительно так. Непроверенные исключения чаще всего являются результатом ошибок программистов.
И компилятор, очевидно, не может предусмотреть все возможные плохие ситуации, которые люди могут создать своими руками. 🙂 Поэтому он не проверяет, обрабатываются ли такие исключения в нашем коде.
Вы уже столкнулись с несколькими непроверенными исключениями:
- При делении на ноль возникает исключение ArithmeticException
- Исключение ArrayIndexOutOfBoundsException возникает, когда вы пытаетесь получить доступ к позиции за пределами массива.
Конечно, можно представить, что создатели Java могли бы ввести обязательную обработку исключений, но в этом случае код получился бы слишком сложным.
Для любой операции деления нужно написать блок try-catch
, чтобы проверить, не произошло ли случайное деление на ноль?
Каждый раз, когда вы обращались к массиву, вам приходилось писать блок try-catch
, чтобы проверить, не вышел ли ваш индекс за границы.
Все будет представлять собой спагетти-код и будет совершенно нечитабельным. Вполне логично, что от этой идеи отказались.
В результате непроверенные исключения не нужно обрабатывать в блоках try-catch
или повторно бросать (хотя технически это возможно, как в случае с Error).
Как бросить собственное исключение
Конечно, создатели Java не могут предусмотреть все исключительные ситуации, которые могут возникнуть в программах. В мире слишком много программ, и они слишком разнообразны.
Но это не повод для беспокойства, ведь при необходимости вы можете создать собственное исключение.
Это очень легко сделать. Все, что вам нужно сделать, – это создать свой собственный класс. Убедитесь, что его имя заканчивается на “Exception”. Компилятор не требует этого, но другие программисты, читающие ваш код, сразу поймут, что это класс исключений.
Кроме того, укажите, что класс наследуется от класса Exception
(компилятор требует этого).
Например, предположим, что у нас есть класс Dog
. Мы можем выгуливать собаку с помощью метода walk()
.
Но перед этим нужно проверить, надеты ли на питомца ошейник, поводок и намордник. Если что-то из этого снаряжения отсутствует, мы выбросим собственное исключение: DogIsNotReadyException. Его код выглядит следующим образом:
public class DogIsNotReadyException extends Exception {
public DogIsNotReadyException(String message) {
super(message);
}
}
Run CodeЧтобы указать, что класс является исключением, нужно написать“extends Exception” после имени класса (это означает, что “класс является производным от класса Exception”).
В конструкторе мы просто вызываем конструктор класса Exception
с сообщением String (если произойдет исключение, мы покажем сообщение, описание ошибки, пользователю).
Вот как это выглядит в коде нашего класса:
public class Dog {
String name;
boolean isCollarPutOn;
boolean isLeashPutOn;
boolean isMuzzlePutOn;
public Dog(String name) {
this.name = name;
}
public static void main(String[] args) {
}
public void putCollar() {
System.out.println("The collar is on!");
this.isCollarPutOn = true;
}
public void putLeash() {
System.out.println("The leash is on!");
this.isLeashPutOn = true;
}
public void putMuzzle() {
System.out.println("The muzzle is on!");
this.isMuzzlePutOn = true;
}
public void walk() throws DogIsNotReadyException {
System.out.println("We're getting ready for a walk!");
if (isCollarPutOn && isLeashPutOn && isMuzzlePutOn) {
System.out.println("Hooray, let's go for a walk! " + name + " is very happy!");
} else {
throw new DogIsNotReadyException(name + " is not ready for a walk! Check the gear!");
}
}
}
Run CodeТеперь наш метод walk()
выбрасывает исключение DogIsNotReadyException. Это делается с помощью ключевого слова throw. Как мы уже говорили, исключение – это объект. Поэтому, когда в нашем методе возникает исключение (собаке чего-то не хватает), мы создаем новый объект DogIsNotReadyException
и бросаем его с помощью ключевого слова throw.
Мы добавляем“throws DogIsNotReadyException” в объявление метода. Другими словами, теперь компилятор знает, что вызов метода walk()
может обернуться исключительной ситуацией.
Соответственно, это исключение должно быть обработано, если мы вызываем этот метод где-то в нашей программе.
Давайте попробуем сделать это в методе main()
:
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.putCollar();
dog.putMuzzle();
dog.walk();// Unhandled exception: DogIsNotReadyException
}
Run CodeЭто не будет компилироваться. Исключение не обработано! Мы обернем наш код в блок try-catch
, чтобы обработать исключение:
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.putCollar();
dog.putMuzzle();
try {
dog.walk();
} catch (DogIsNotReadyException e) {
System.out.println(e.getMessage());
System.out.println("Checking the gear! Is the collar on? " + dog.isCollarPutOn + "\r\n Is the leash on? "
+ dog.isLeashPutOn + "\r\n Is the muzzle on? " + dog.isMuzzlePutOn);
}
}
Run CodeТеперь давайте посмотрим на вывод консоли:
The collar is on!
The muzzle is on!
We’re getting ready for a walk!
Buddy is not ready for a walk! Check the gear!
Checking the gear! Is the collar on? true
Is the leash on? false
Is the muzzle on? true
Посмотрите, насколько информативнее стал консольный вывод!
Мы видим каждый шаг программы, видим, где произошла ошибка, а также можем сразу понять, чего именно не хватает нашей собаке. 🙂
Вот так вы создаете свои собственные исключения. Как видите, ничего сложного в этом нет. И хотя создатели Java не удосужились включить в язык специальное исключение для плохо экипированных собак, мы исправили их недосмотр. 🙂
Перевод статьи «Exceptions: checked, unchecked, and custom».