Расскажи про иерархию исключений
Иерархия исключений в Java — это дерево наследования классов, корнем которого является класс Throwable, разделяющийся на два основных подкласса: Error и Exception. Эта структура позволяет единообразно обрабатывать ошибки и исключительные ситуации, различая фатальные проблемы виртуальной машины и ошибки, которые приложение может предвидеть и обработать.
Как это работает
Класс Throwable — базовый для всех исключений и ошибок. Он содержит ключевые методы: getMessage() для получения сообщения, getCause() для доступа к причине исключения, printStackTrace() для вывода стека вызовов, а также методы для подавления исключений (addSuppressed(), getSuppressed()). От Throwable наследуются два класса:
Error— представляет серьёзные проблемы, возникающие на уровне JVM или системных ресурсов. Примеры:OutOfMemoryError,StackOverflowError. Такие ошибки обычно не обрабатываются приложением, так как восстановление невозможно или нецелесообразно.Exception— описывает исключительные ситуации, с которыми программа может справиться. В свою очередь делится на проверяемые и непроверяемые исключения.
Проверяемые и непроверяемые исключения
Проверяемые исключения (checked exceptions) — это подклассы Exception, кроме RuntimeException и его наследников. Компилятор требует их обязательной обработки: либо в блоке try-catch, либо объявлением в сигнатуре метода через throws. Они сигнализируют о внешних условиях, которые программа может предвидеть, например, ошибки ввода-вывода или отсутствие класса. Примеры: IOException, FileNotFoundException, ClassNotFoundException.
Непроверяемые исключения (unchecked exceptions) — это RuntimeException и его подклассы, а также Error. Они возникают из-за ошибок программирования или некорректных данных, например, NullPointerException, ClassCastException, ArrayIndexOutOfBoundsException. Обработка таких исключений не обязательна: компилятор не требует ни try-catch, ни throws.
Пример
import java.io.*;
public class ExceptionHierarchyExample {
public static void main(String[] args) {
// Проверяемое исключение: обязаны обработать или объявить throws
try {
readFile("data.txt");
} catch (IOException e) {
System.out.println("Ошибка ввода-вывода: " + e.getMessage());
}
// Непроверяемое исключение: можно не обрабатывать
String s = null;
if (s.length() > 0) { // NullPointerException
System.out.println(s);
}
}
static void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
reader.close();
}
}Подводные камни
- Не перехватывайте
Error— это не даст приложению корректно завершиться при серьёзных сбоях, например, при нехватке памяти. - Проверяемые исключения могут загромождать код, если злоупотреблять
throwsилиcatchбез реальной обработки. - Собственные исключения обычно наследуют от
Exception(если они проверяемые) или отRuntimeException(если непроверяемые). Выбор зависит от того, должна ли вызывающая сторона быть обязана их обрабатывать. - Не используйте исключения для управления нормальным потоком выполнения — это снижает производительность и читаемость.
Когда использовать
- Проверяемые исключения — для ситуаций, которые вызывающий код обязан предусмотреть: ошибки ввода-вывода, отсутствие файлов, проблемы с сетью.
- Непроверяемые — для ошибок программирования (некорректные аргументы, нарушение контракта) и внутренних состояний, которые не должны возникать при корректной работе.
Error— не обрабатывайте, но учитывайте при проектировании надёжных систем (например, логируйте и завершайте работу).
Коротко
- Корень иерархии —
Throwable, от него наследуютсяErrorиException. Error— фатальные проблемы JVM, не обрабатываются.Exceptionделится на проверяемые (обязательныtry-catchилиthrows) и непроверяемые (RuntimeException, не обязательны).- Проверяемые —
IOException,ClassNotFoundException; непроверяемые —NullPointerException,ClassCastException.
