← Назад к вопросам

В чем разница между Checked и Runtime Exception?

1.0 Junior🔥 251 комментариев
#ООП#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между Checked и Runtime Exception

Это одна из фундаментальных концепций Java. Различие состоит в том, как компилятор их обрабатывает и когда они возникают.

Иерархия Exception в Java

Throwable
├── Error (критичные ошибки, перезагружать JVM)
└── Exception
    ├── Checked Exception (наследники Exception кроме RuntimeException)
    │   ├── IOException
    │   ├── SQLException
    │   ├── FileNotFoundException
    │   └── CustomCheckedException
    │
    └── Unchecked Exception (RuntimeException и его наследники)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        ├── IllegalArgumentException
        └── ArithmeticException

Checked Exception (Проверяемые исключения)

Определение: Исключения, которые компилятор заставляет обрабатывать (catch или throws).

Наследуют от: Exception (но не от RuntimeException)

Когда возникают: В runtime, но должны быть обработаны в compile time

// ✅ Правильно — обработано или объявлено
public class FileReader {
    // Способ 1: Catch
    public String readFile(String path) {
        try {
            FileInputStream fis = new FileInputStream(path);
            // ...
        } catch (FileNotFoundException e) {
            System.err.println("Файл не найден: " + e.getMessage());
            return null;
        }
    }
    
    // Способ 2: Throws
    public String readFileThrows(String path) throws FileNotFoundException, IOException {
        FileInputStream fis = new FileInputStream(path);
        // ...
        return content;
    }
}

// ❌ Ошибка компиляции — checked exception не обработано
public String readFile(String path) {
    FileInputStream fis = new FileInputStream(path); // Ошибка компиляции!
    return "content";
}

Примеры Checked Exception:

// IOException — checked exception
try {
    FileInputStream fis = new FileInputStream("file.txt");
} catch (FileNotFoundException e) {
    e.printStackTrace();
}

// SQLException — checked exception (база данных)
try {
    Connection conn = DriverManager.getConnection(url);
} catch (SQLException e) {
    e.printStackTrace();
}

// InterruptedException — checked exception (потоки)
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}

Создание собственного Checked Exception:

// Наследуем от Exception
public class InvalidUserException extends Exception {
    public InvalidUserException(String message) {
        super(message);
    }
    
    public InvalidUserException(String message, Throwable cause) {
        super(message, cause);
    }
}

// Использование
public User getUser(Long id) throws InvalidUserException {
    if (id == null || id <= 0) {
        throw new InvalidUserException("User ID must be positive");
    }
    // ...
}

// Обработка
try {
    User user = getUser(-1);
} catch (InvalidUserException e) {
    System.err.println("Invalid user: " + e.getMessage());
}

Runtime Exception (Неоковиваемые исключения)

Определение: Исключения, которые компилятор НЕ заставляет обрабатывать.

Наследуют от: RuntimeException (который наследует от Exception)

Когда возникают: В runtime, но могут остаться необработанными

// ✅ Компилируется, даже без try-catch
public int divide(int a, int b) {
    return a / b; // RuntimeException: ArithmeticException (если b == 0)
}

// Использование без обработки
int result = divide(10, 0); // Приложение упадёт если b == 0

// Но можно обработать, если хочешь
try {
    int result = divide(10, 0);
} catch (ArithmeticException e) {
    System.err.println("Деление на ноль: " + e.getMessage());
}

Примеры Runtime Exception:

// NullPointerException
String str = null;
int length = str.length(); // NPE!

// ArrayIndexOutOfBoundsException
int[] arr = new int[5];
int val = arr[10]; // ArrayIndexOutOfBoundsException!

// IllegalArgumentException
public void setAge(int age) {
    if (age < 0) {
        throw new IllegalArgumentException("Age cannot be negative");
    }
    this.age = age;
}

// ClassCastException
Object obj = "string";
Integer num = (Integer) obj; // ClassCastException!

Создание собственного Runtime Exception:

// Наследуем от RuntimeException
public class InvalidOperationException extends RuntimeException {
    public InvalidOperationException(String message) {
        super(message);
    }
}

// Использование — можно не ловить
public void performAction(String action) {
    if (action == null) {
        throw new InvalidOperationException("Action cannot be null");
    }
    // ...
}

// Компилируется, даже без try-catch
performAction(null); // Вызовет InvalidOperationException

Сравнительная таблица

АспектChecked ExceptionRuntime Exception
Наследует отExceptionRuntimeException
Обязательная обработкаДа (компилятор заставляет)Нет (опционально)
Когда возникаетRuntimeRuntime
ПримерыIOException, SQLExceptionNullPointerException, IllegalArgumentException
ПроизводительностьНемного медленнееБыстрее
ИспользованиеПредсказуемые ошибкиНепредсказуемые ошибки программы

Когда использовать какой?

Используй Checked Exception когда:

  1. Ошибка вероятна и предсказуема
  2. Клиент кода может разумно восстановиться
  3. Это внешний ресурс (файлы, БД, сеть)
public class DatabaseService {
    // Checked exception — клиент должен знать о возможной ошибке
    public User getUserFromDB(Long id) throws SQLException {
        // Может выбросить SQLException — нужно обработать
    }
}

// Клиент кода
try {
    User user = databaseService.getUserFromDB(1);
} catch (SQLException e) {
    // Может переподключиться, логировать, уведомить пользователя
    logger.error("Database error: " + e.getMessage());
}

Используй Runtime Exception когда:

  1. Ошибка указывает на проблему в коде (баг)
  2. Клиент кода не может разумно восстановиться
  3. Это программная ошибка (проверяющая инварианты)
public class UserService {
    // Runtime exception — ошибка в коде клиента
    public void setAge(int age) {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative");
        }
        this.age = age;
    }
}

// Клиент просто передаёт правильные данные
userService.setAge(25); // OK
userService.setAge(-5); // IllegalArgumentException — баг в клиенте

Практические примеры

Checked Exception — IO операции:

public class FileLogger {
    public void log(String message) throws IOException {
        try (FileWriter fw = new FileWriter("log.txt", true)) {
            fw.write(message + "\n");
        } // IOException — checked, должна быть обработана
    }
}

// Использование
try {
    logger.log("User logged in");
} catch (IOException e) {
    System.err.println("Failed to log: " + e.getMessage());
}

Runtime Exception — валидация данных:

public class User {
    private String email;
    
    public void setEmail(String email) {
        if (email == null || email.isEmpty()) {
            throw new IllegalArgumentException("Email cannot be empty");
        }
        if (!email.contains("@")) {
            throw new IllegalArgumentException("Invalid email format");
        }
        this.email = email;
    }
}

// Использование — обработка необязательна
User user = new User();
user.setEmail("invalid"); // IllegalArgumentException

Современный подход (Java 8+)

В современной Java часто избегают checked exceptions в пользу:

// Вместо checked exception — Optional
public Optional<User> findUser(Long id) {
    // Нет throws, но может вернуть empty
    return userRepository.findById(id);
}

// Использование
User user = userService.findUser(1).orElse(null);

Или использовать Result type:

public class Result<T> {
    private final T value;
    private final Exception error;
    
    public static <T> Result<T> success(T value) {
        return new Result<>(value, null);
    }
    
    public static <T> Result<T> failure(Exception error) {
        return new Result<>(null, error);
    }
}

public Result<User> getUserFromDB(Long id) {
    try {
        return Result.success(database.getUser(id));
    } catch (SQLException e) {
        return Result.failure(e);
    }
}

Вывод

Checked Exception:

  • Обязательная обработка
  • Для предсказуемых ошибок (IO, БД, сеть)
  • Заставляет клиента думать об ошибках

Runtime Exception:

  • Опциональная обработка
  • Для программных ошибок (баги)
  • Более гибкие для использования

Модернизм Java идёт в сторону Runtime Exceptions и функциональных типов (Optional, Result), нежели классических Checked Exceptions.