1. Класс Throwable: корень всех исключений
Сейчас мы подробно разберём, как устроена система исключений в Java: что такое Throwable, чем отличаются Exception и Error, а также что значит «проверяемое» и «непроверяемое» исключение. Это фундамент для грамотной обработки ошибок в ваших программах.
В Java все исключения и ошибки — это объекты, которые наследуются от класса java.lang.Throwable.
Throwable — это «прародитель» всей иерархии обработки проблем в Java.
Схематично:
Throwable
├── Exception
└── Error
Throwable — базовый класс для всего, что может быть «выброшено» (throw) и «поймано» (catch) в Java. Его нельзя использовать напрямую — он служит основой для более конкретных типов ошибок.
Exception — для «нормальных» ошибок
Exception — базовый класс для всех исключений, которые могут возникнуть в программе и которые можно и нужно обрабатывать. Это «рабочие» ошибки: проблемы с файлами, сетью, вводом-выводом, ошибками пользователя и т. д. Большинство ваших try-catch будет работать именно с наследниками Exception.
Примеры:
- IOException — ошибка при работе с файлами или сетью.
- SQLException — ошибка при работе с базой данных.
- FileNotFoundException — файл не найден.
Error — для фатальных ошибок JVM
Error — базовый класс для ошибок, которые происходят на уровне виртуальной машины Java (JVM). Обычно это критические сбои, которые программа не может и не должна обрабатывать. Если возник Error — скорее всего, приложение не сможет продолжить работу.
Примеры:
- OutOfMemoryError — закончилась память.
- StackOverflowError — переполнение стека (например, из-за бесконечной рекурсии).
- NoClassDefFoundError — не найден нужный класс.
Важно:
Ловить и обрабатывать Error — почти всегда плохая идея. Это не ошибки вашей программы, а сбои среды выполнения.
2. Checked vs Unchecked exceptions: что это значит?
В Java все исключения делятся на две большие группы:
Проверяемые (Checked) исключения
Что это? Исключения, которые компилятор заставляет обработать или явно пробросить дальше.
Когда возникают? Обычно связаны с внешними ресурсами: файлами, сетью, базами данных, вводом пользователя.
Как обрабатывать? Нужно либо обернуть код в try-catch, либо добавить throws в сигнатуру метода.
Примеры: IOException, SQLException, FileNotFoundException
Пример:
public void readFile(String path) throws IOException {
FileReader reader = new FileReader(path); // может выбросить IOException
// ...
}
Если не обработать или не пробросить — программа не скомпилируется!
Непроверяемые (Unchecked) исключения
Что это? Исключения, которые не требуют обязательной обработки компилятором.
Когда возникают? Обычно это ошибки в логике программы: деление на ноль, выход за границы массива, обращение к null.
Как обрабатывать? Можно ловить, но не обязательно. Лучше предотвращать такие ошибки с помощью проверок.
Где в иерархии? Все наследуют от RuntimeException.
Примеры: NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException
Пример:
int[] arr = {1, 2, 3};
System.out.println(arr[10]); // ArrayIndexOutOfBoundsException
Компилятор не заставляет вас ловить это исключение — но программа «упадёт» при ошибке.
3. Вся иерархия на одной картинке
graph TD
Throwable --> Error
Throwable --> Exception
Exception --> RuntimeException
Exception --> CheckedExceptions["(другие Checked Exceptions)"]
Error --> OutOfMemoryError
Error --> StackOverflowError
RuntimeException --> NullPointerException
RuntimeException --> IndexOutOfBoundsException
RuntimeException --> IllegalArgumentException
%% Стили
style Throwable fill:#ffa64d,color:#000
style Exception fill:#ffa64d,color:#000
style CheckedExceptions fill:#ffa64d,color:#000
style Error fill:#ff4d4d,color:#fff
style OutOfMemoryError fill:#ff4d4d,color:#fff
style StackOverflowError fill:#ff4d4d,color:#fff
style RuntimeException fill:#4dff88,color:#000
style NullPointerException fill:#4dff88,color:#000
style IndexOutOfBoundsException fill:#4dff88,color:#000
style IllegalArgumentException fill:#4dff88,color:#000
Таблица: основные различия
| Группа | Родительский класс | Требует обработки? | Примеры |
|---|---|---|---|
| Checked Exception | |
Да | |
| Unchecked | |
Нет | |
| Error | |
Нет | |
4. Как это выглядит в коде?
Checked Exception: пример с файлами
import java.io.*;
public class FileDemo {
public static void main(String[] args) {
try {
FileReader reader = new FileReader("nofile.txt"); // FileNotFoundException (checked)
int data = reader.read();
System.out.println(data);
reader.close();
} catch (IOException e) {
System.out.println("Ошибка при работе с файлом: " + e.getMessage());
}
}
}
Компилятор заставит обработать IOException!
Unchecked Exception: пример с делением на ноль
public class ExceptionDemo {
public static void main(String[] args) {
int a = 10;
int b = 0;
int c = a / b; // ArithmeticException (unchecked)
System.out.println("Результат: " + c);
}
}
Компилятор не требует обработки, но программа «упадёт».
5. Зачем нужна иерархия исключений?
- Гибкость обработки: Можно ловить как конкретные ошибки (FileNotFoundException), так и целые группы (IOException или Exception).
- Переиспользование кода: Можно централизованно обрабатывать ошибки одного типа.
- Чистота кода: Основная логика не засоряется проверками на каждую мелочь.
Пример:
try {
// опасный код
} catch (FileNotFoundException e) {
System.out.println("Файл не найден!");
} catch (IOException e) {
System.out.println("Ошибка ввода-вывода!");
} catch (Exception e) {
System.out.println("Что-то пошло не так: " + e.getMessage());
}
6. Типичные ошибки при работе с исключениями
Ошибка № 1: Игнорирование исключений. Писать catch (Exception e) {} — плохо! Вы теряете информацию о причине ошибки.
Ошибка № 2: Ловим слишком много. catch (Exception e) ловит всё подряд, даже то, что не ожидали. Лучше ловить только те исключения, которые умеете обрабатывать.
Ошибка № 3: Ловим ошибки (Error). Не стоит ловить Error, если вы не пишете низкоуровневый код. Это проблемы JVM, а не вашей программы.
Ошибка № 4: Не различаем checked и unchecked. Не все исключения одинаковы! Checked требуют обработки (Exception), unchecked — нет (RuntimeException и наследники).
Ошибка № 5: Не добавляем информацию в исключения. Если создаёте свои исключения — всегда добавляйте информативное сообщение.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
картинке