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

Что такое проверяемые исключения?

1.7 Middle🔥 171 комментариев
#Основы Java

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

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

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

Что такое проверяемые исключения (Checked Exceptions)?

Проверяемые исключения — это исключения, которые компилятор ОБЯЗЫВАЕТ обработать или объявить. Если вы этого не сделаете — код не скомпилируется.

Иерархия исключений в Java

Throwable (корень всех ошибок)
├── Exception (можно обработать)
│   ├── Checked Exception (IOException, SQLException, ...)
│   └── RuntimeException (NullPointerException, IndexOutOfBoundsException, ...)
└── Error (нельзя обработать, критичные ошибки)
    ├── OutOfMemoryError
    ├── StackOverflowError
    └── VirtualMachineError

Проверяемые — наследники Exception (кроме RuntimeException). НепроверяемыеRuntimeException и Error.

Примеры проверяемых исключений

import java.io.*;

// IOException — проверяемое
public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);  // Может выбросить IOException
    // ...
}

// SQLException — проверяемое
public User getUserFromDB(int id) throws SQLException {
    // SELECT * FROM users WHERE id = ?
    // Может выбросить SQLException
    return null;
}

// ParseException — проверяемое
public LocalDate parseDate(String date) throws ParseException {
    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
    return format.parse(date);  // Может выбросить ParseException
}

Обязательная обработка

Вариант 1: Try-Catch (обработка)

public void processFile(String path) {
    try {
        FileReader reader = new FileReader(path);
        // Код обработки файла
    } catch (FileNotFoundException e) {
        System.err.println("Файл не найден: " + e.getMessage());
    } catch (IOException e) {
        System.err.println("Ошибка чтения: " + e.getMessage());
    }
}

Вариант 2: Throws (переброска)

// Говорим компилятору: "Я не буду это обрабатывать, пусть вызывающий код справляется"
public void processFile(String path) throws IOException {
    FileReader reader = new FileReader(path);  // IOException выбросится наверх
}

// Тогда вызывающий код ДОЛЖЕН обработать
public void runApplication() throws IOException {
    processFile("data.txt");  // Или try-catch
}

Разница: Checked vs Unchecked

// ✅ Checked Exception — ОБЯЗАТЕЛЬНО обработать
try {
    Thread.sleep(1000);  // InterruptedException — checked
} catch (InterruptedException e) {
    e.printStackTrace();
}

// ❌ Непроверяемое исключение — опционально обработать
try {
    int[] arr = new int[5];
    int x = arr[10];  // ArrayIndexOutOfBoundsException — unchecked
} catch (ArrayIndexOutOfBoundsException e) {
    // Это необязательно, но можно
    e.printStackTrace();
}

Когда вы NOT обработаете checked exception

// ❌ ОШИБКА КОМПИЛЯЦИИ
public void badMethod() {
    FileReader reader = new FileReader("file.txt");  // FileNotFoundException extends IOException
    // Компилятор скажет:
    // "Unhandled exception: java.io.IOException"
}

// ✅ ПРАВИЛЬНО (вариант 1)
public void goodMethod1() throws IOException {
    FileReader reader = new FileReader("file.txt");
}

// ✅ ПРАВИЛЬНО (вариант 2)
public void goodMethod2() {
    try {
        FileReader reader = new FileReader("file.txt");
    } catch (IOException e) {
        // Обработка
    }
}

Практический пример: работа с БД

public class UserRepository {
    
    // Вариант 1: throws (переброска)
    public User findById(int id) throws SQLException {
        String sql = "SELECT * FROM users WHERE id = ?";
        Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/db");
        // Может выбросить SQLException
        return null;
    }
    
    // Вариант 2: try-catch (обработка)
    public User findByIdSafe(int id) {
        try {
            String sql = "SELECT * FROM users WHERE id = ?";
            Connection conn = DriverManager.getConnection("jdbc:mysql://localhost/db");
            // SELECT, обработка результата
            return null;
        } catch (SQLException e) {
            System.err.println("Database error: " + e.getMessage());
            return null;  // Или выбросить custom exception
        }
    }
}

// Вызывающий код ДОЛЖЕН обработать
public class UserService {
    private final UserRepository repo;
    
    public void processUser(int userId) throws SQLException {
        User user = repo.findById(userId);  // throws SQLException
        // ...
    }
}

Полезный паттерн: Try-with-resources

Для автоматического закрытия ресурсов:

// ✅ Современный способ (Java 7+)
public void readFile(String path) throws IOException {
    try (FileReader reader = new FileReader(path);  // Автоматически закроется
         BufferedReader buffered = new BufferedReader(reader)) {
        String line;
        while ((line = buffered.readLine()) != null) {
            System.out.println(line);
        }
    }  // FileReader и BufferedReader закроются автоматически
}

// ❌ Старый способ (до Java 7)
public void readFileOld(String path) throws IOException {
    FileReader reader = null;
    try {
        reader = new FileReader(path);
        // обработка
    } finally {
        if (reader != null) {
            reader.close();  // Нужно закрывать вручную
        }
    }
}

Контроверсия: Полезны ли проверяемые исключения?

За (классический Java подход): ✓ Явная сигнализация об ошибках ✓ Разработчик ДОЛЖЕН подумать об ошибках ✓ Безопасность

Против (современный подход): ✗ Много boilerplate кода ✗ Переброска throws растёт вверх по стеку ✗ Часто просто ловят и игнорируют ✗ Java 8+ потоки не поддерживают throws

// Проблема с потоками
List<String> files = Arrays.asList("file1.txt", "file2.txt");

// ❌ Не компилируется!
files.forEach(file -> readFile(file));  // readFile throws IOException

// ✅ Нужно обернуть в try-catch
files.forEach(file -> {
    try {
        readFile(file);
    } catch (IOException e) {
        e.printStackTrace();
    }
});

Best Practice в современном Java

// ✅ Оборачивать checked в unchecked
public User findUserById(int id) {  // Без throws!
    try {
        // Database call
        return getUserFromDB(id);  // throws SQLException
    } catch (SQLException e) {
        throw new RuntimeException("Database error", e);  // Wrap in unchecked
    }
}

// Тогда вызывающий код не обязан обрабатывать
User user = findUserById(123);  // No try-catch needed

Вывод

Проверяемые исключения:

  • ✅ Заставляют думать об ошибках
  • ❌ Добавляют boilerplate
  • ⚡ Часто оборачивают в RuntimeException
  • 📌 Используются в I/O, SQL, сетевых операциях

Модернизированный Java предпочитает unchecked exceptions, но проверяемые остаются частью стандартной библиотеки.

Что такое проверяемые исключения? | PrepBro