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

Для чего нужно checked исключение?

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

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

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

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

# Checked Исключение (Checked Exception)

Определение

Checked исключение — это исключение, которое обязательно должно быть обработано или объявлено в сигнатуре метода с помощью ключевого слова throws. Компилятор Java проверяет это и не компилирует код, если checked исключение не обработано. Checked исключение наследуется от класса Exception (но НЕ от RuntimeException).

Основное назначение

1. Различие между Checked и Unchecked исключениями

// CHECKED исключение (наследуется от Exception напрямую)
public class FileNotFoundException extends IOException { }
public class SQLException extends Exception { }

// Компилятор ТРЕБУЕТ обработку или throws
public void readFile(String path) throws FileNotFoundException {
    // Обязательно указать throws
    FileReader reader = new FileReader(path);  // Throws FileNotFoundException
}

// UNCHECKED исключение (наследуется от RuntimeException)
public class NullPointerException extends RuntimeException { }

// Компилятор НЕ требует обработку
public void printLength(String str) {
    System.out.println(str.length());  // Может выбросить NPE, но это OK
}

2. Когда выбрасываются Checked исключения

Операции с файлами:

// IOException и FileNotFoundException — checked
public String readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);  // Throws FileNotFoundException
    BufferedReader buffered = new BufferedReader(reader);
    String content = buffered.readLine();      // Throws IOException
    reader.close();                             // Throws IOException
    return content;
}

// Использование
try {
    String content = readFile("config.txt");
} catch (FileNotFoundException e) {
    System.out.println("File not found: " + e.getMessage());
} catch (IOException e) {
    System.out.println("Error reading file: " + e.getMessage());
}

Операции с БД:

// SQLException — checked
public List<User> getAllUsers() throws SQLException {
    Connection conn = getConnection();  // Throws SQLException
    Statement stmt = conn.createStatement();  // Throws SQLException
    ResultSet rs = stmt.executeQuery("SELECT * FROM users");  // Throws SQLException
    return mapToUsers(rs);
}

// Использование
try {
    List<User> users = getAllUsers();
} catch (SQLException e) {
    System.out.println("Database error: " + e.getMessage());
    // Логирование, откат транзакции и т.д.
}

Сетевые операции:

// IOException — checked
public String fetchData(String url) throws IOException {
    URL urlObj = new URL(url);
    HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();  // IOException
    BufferedReader reader = new BufferedReader(
        new InputStreamReader(conn.getInputStream())  // IOException
    );
    String line = reader.readLine();  // IOException
    return line;
}

// Использование
try {
    String data = fetchData("https://api.example.com/data");
} catch (IOException e) {
    System.out.println("Network error: " + e.getMessage());
    // Повтор запроса или использование fallback
}

3. Принцип работы Checked исключений

// Метод должен либо обработать, либо объявить throws
public void processData(String filename) {
    try {
        readFile(filename);  // IOException — checked
    } catch (IOException e) {
        System.out.println("Обработка ошибки");
    }
    // ИЛИ
}

public void processData(String filename) throws IOException {
    readFile(filename);  // IOException — checked, но объявлена в throws
}

public void readFile(String filename) throws IOException {
    FileReader reader = new FileReader(filename);
}

4. Распространение Checked исключений

// Если не обработать, то ОБЯЗАТЕЛЬНО объявить throws
public void method1() throws IOException {
    method2();  // IOException распространяется
}

public void method2() throws IOException {
    method3();  // IOException распространяется
}

public void method3() throws IOException {
    readFile("data.txt");  // IOException выбрасывается здесь
}

// Вызов
try {
    method1();
} catch (IOException e) {
    System.out.println("Error in chain: " + e.getMessage());
}

5. Обработка множественных Checked исключений

public class DataProcessor {
    
    public void process(String filepath) throws IOException, SQLException {
        String data = readFile(filepath);      // Throws IOException
        List<User> users = parseUsers(data);
        saveToDatabase(users);                 // Throws SQLException
    }
    
    private String readFile(String path) throws IOException {
        FileReader reader = new FileReader(path);
        // ...
        return content;
    }
    
    private void saveToDatabase(List<User> users) throws SQLException {
        Connection conn = getConnection();
        // ...
    }
}

// Использование
try {
    processor.process("users.csv");
} catch (IOException e) {
    System.out.println("File error: " + e.getMessage());
} catch (SQLException e) {
    System.out.println("Database error: " + e.getMessage());
}

6. Создание собственного Checked исключения

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

public class AuthService {
    
    public User login(String email, String password) 
            throws InvalidCredentialsException {
        
        User user = findByEmail(email);
        
        if (user == null) {
            throw new InvalidCredentialsException(
                "User not found: " + email
            );
        }
        
        if (!user.getPassword().equals(hashPassword(password))) {
            throw new InvalidCredentialsException(
                "Invalid password for user: " + email
            );
        }
        
        return user;
    }
}

// Использование
try {
    User user = authService.login("john@example.com", "password123");
    System.out.println("Login successful: " + user.getName());
} catch (InvalidCredentialsException e) {
    System.out.println("Login failed: " + e.getMessage());
}

7. Примеры встроенных Checked исключений

// IOException и подклассы
throws FileNotFoundException;   // Файл не найден
throws SocketException;          // Проблема с сокетом
throws EOFException;             // Конец файла

// SQLException
throws SQLException;             // Ошибка БД

// Reflection
throws ClassNotFoundException;   // Класс не найден
throws NoSuchMethodException;    // Метод не найден

// Java Naming and Directory Interface
throws NamingException;          // JNDI ошибка

// JSON
throws ParseException;           // Ошибка парсинга

8. Try-with-resources для Checked исключений

// Старый подход (много кода)
public String readFile(String path) throws IOException {
    FileReader reader = null;
    try {
        reader = new FileReader(path);
        return reader.readLine();
    } finally {
        if (reader != null) {
            reader.close();  // Throws IOException
        }
    }
}

// Новый подход (Java 7+) — автоматическое закрытие ресурсов
public String readFile(String path) throws IOException {
    try (FileReader reader = new FileReader(path);  // Throws IOException
         BufferedReader buffered = new BufferedReader(reader)) {
        return buffered.readLine();
    }
    // reader и buffered автоматически закрыты
}

9. Обёртывание Checked в Unchecked (AntiPattern)

// ПЛОХО — скрывать checked исключение в unchecked
public String readFile(String path) {
    try {
        FileReader reader = new FileReader(path);
        return reader.readLine();
    } catch (IOException e) {
        throw new RuntimeException(e);  // Плохая практика!
    }
}

// ХОРОШО — явно объявить throws
public String readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);
    return reader.readLine();
}

// Если нужно обернуть:
public String readFile(String path) throws DataAccessException {
    try {
        FileReader reader = new FileReader(path);
        return reader.readLine();
    } catch (IOException e) {
        throw new DataAccessException("Failed to read file: " + path, e);
    }
}

10. Сравнение Checked vs Unchecked (повторение)

ПараметрCheckedUnchecked
НаследникExceptionRuntimeException
Проверка компиляторомДа (обязательно)Нет
throws в сигнатуреОбязателенНе требуется
try-catchОбязателенОпционален
ИспользованиеОшибки окруженияОшибки программиста
ПримерыIOException, SQLExceptionNPE, IndexOutOfBoundsException
Когда выбрасываетсяI/O, БД, сетьОшибки логики

Выводы

Checked исключение нужно для:

  • Обозначения ошибок окружения, которые нельзя предотвратить (файл удалён, сеть упала)
  • Принуждения программиста к обработке возможных ошибок
  • Сигнализирования о том, что метод может выбросить исключение
  • Разделения ответственности между разработчиком и окружением

Это фундаментальный механизм Java для обработки ошибок, обеспечивающий надёжность приложений через compile-time безопасность. Хорошее приложение правильно использует checked исключения для I/O и external системы.