Ответ
Различие основано на обязательности обработки на этапе компиляции.
| Критерий | Checked Exceptions (Проверяемые) | Unchecked Exceptions (Непроверяемые / Runtime) |
|---|---|---|
| Наследование | Классы, наследующие от java.lang.Exception, но не от RuntimeException. |
Классы, наследующие от java.lang.RuntimeException (а она — от Exception). |
| Проверка компилятором | Да. Компилятор требует либо обработать исключение в try-catch, либо объявить в throws сигнатуре метода. |
Нет. Компилятор не требует их явного объявления или обработки. |
| Когда возникают | Внешние, часто восстанавливаемые условия, на которые программа может повлиять (отсутствие файла, разрыв сети, ошибка БД). | Внутренние ошибки программиста или логики приложения (обращение к null, неверный индекс массива, ошибка бизнес-логики). |
| Примеры | IOException, SQLException, ClassNotFoundException, FileNotFoundException. |
NullPointerException, ArrayIndexOutOfBoundsException, IllegalArgumentException, ArithmeticException. |
| Best Practice | Использовать для ошибок, которые разумно ожидать и от которых вызывающий код может восстановиться. | Использовать для ошибок, которые указывают на баг в программе и от которых обычно нельзя корректно восстановиться. |
Пример кода:
// CHECKED Исключение: Компилятор заставит его обработать.
public String readConfigFile(String path) throws IOException { // Объявляем в throws
return Files.readString(Path.of(path)); // Может выбросить FileNotFoundException (checked)
}
// Или обрабатываем:
public String readConfigFileSafe(String path) {
try {
return Files.readString(Path.of(path));
} catch (IOException e) { // Ловим checked исключение
return "default"; // Восстанавливаемся
}
}
// UNCHECKED Исключение: Компилятор не проверяет.
public int calculateDiscount(int price, int percent) {
if (percent < 0 || percent > 100) {
// Ошибка программиста/логики. Бросаем unchecked исключение.
throw new IllegalArgumentException("Процент должен быть от 0 до 100");
}
return price * percent / 100;
}
// Вызывающий код может, но не обязан, ловить его.
public void applyDiscount() {
try {
calculateDiscount(100, 150); // Выбросит IllegalArgumentException
} catch (IllegalArgumentException e) {
System.err.println("Неверные входные данные: " + e.getMessage());
}
}
Современный подход (с Java 8+): Часто предпочтение отдается unchecked-исключениям, чтобы не загромождать код. Checked-исключения уместны, когда вызывающая сторона действительно может предпринять осмысленные действия для восстановления.