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

Как компиляция программы влияет на появление исключений

2.2 Middle🔥 161 комментариев
#ООП#Основы Java

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

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

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

Влияние компиляции на исключения в Java

Это важная тема, которая касается разницы между compile-time и runtime ошибками.

1. Compile-time исключения (Checked Exceptions)

Проверяются компилятором и ДОЛЖНЫ быть обработаны:

import java.io.*;

public class FileProcessor {
    // Метод объявляет проверяемое исключение
    public String readFile(String filename) throws IOException {
        // IOException — checked exception, требует обработки
        BufferedReader reader = new BufferedReader(new FileReader(filename));
        String line = reader.readLine();
        reader.close();
        return line;
    }
    
    // Вариант 1: throws (передаём ответственность выше)
    public void processFile(String filename) throws IOException {
        String content = readFile(filename);
        System.out.println(content);
    }
    
    // Вариант 2: try-catch (обрабатываем)
    public void processFileWithHandler(String filename) {
        try {
            String content = readFile(filename);
            System.out.println(content);
        } catch (IOException e) {
            System.err.println("Ошибка чтения файла: " + e.getMessage());
        }
    }
    
    // Вариант 3: try-with-resources (автоматическое закрытие ресурсов)
    public String readFileSafe(String filename) throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader(filename))) {
            return reader.readLine();
        } // reader закроется автоматически
    }
}

// Если не обработать — КОД НЕ СКОМПИЛИРУЕТСЯ!
// Error: unhandled exception type IOException

2. Runtime исключения (Unchecked Exceptions)

Не проверяются компилятором, но могут возникнуть во время выполнения:

public class ArithmeticExample {
    // КОМПИЛИРУЕТСЯ БЕЗ ОШИБОК
    public int divide(int a, int b) {
        return a / b; // ArithmeticException при b == 0
    }
    
    // КОМПИЛИРУЕТСЯ БЕЗ ОШИБОК
    public void accessArray(int[] arr, int index) {
        System.out.println(arr[index]); // ArrayIndexOutOfBoundsException
    }
    
    // КОМПИЛИРУЕТСЯ БЕЗ ОШИБОК
    public String getString(Object obj) {
        return (String) obj; // ClassCastException
    }
    
    // КОМПИЛИРУЕТСЯ БЕЗ ОШИБОК
    public void nullPointer() {
        String str = null;
        int len = str.length(); // NullPointerException
    }
    
    // Обработка опциональна, но рекомендуется
    public void safeArithmetic(int a, int b) {
        try {
            int result = divide(a, b);
            System.out.println("Результат: " + result);
        } catch (ArithmeticException e) {
            System.err.println("Деление на ноль!");
        }
    }
}

3. Иерархия исключений

// Класс Exception — иерархия
Throwable
├── Error (fatal, не обрабатываем)
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── VirtualMachineError
├── Exception
│   ├── Checked (ДОЛЖНЫ быть обработаны)
│   │   ├── IOException
│   │   ├── SQLException
│   │   ├── FileNotFoundException
│   │   └── ClassNotFoundException
│   └── RuntimeException (Unchecked, опционально)
│       ├── NullPointerException
│       ├── ArrayIndexOutOfBoundsException
│       ├── ClassCastException
│       ├── IllegalArgumentException
│       └── ArithmeticException

4. Влияние на компиляцию: примеры

import java.sql.SQLException;
import java.io.IOException;

public class CompilationExample {
    // ОШИБКА 1: Unchecked exception в throws — странно, но разрешено
    public void method1() throws NullPointerException {
        // Компилируется, но это плохая практика
        String str = null;
        System.out.println(str.length());
    }
    
    // ОШИБКА 2: Забыли обработать checked exception
    // public void readFromDatabase() {
    //     Connection conn = DriverManager.getConnection("...");
    //     // Compilation error: unhandled exception type SQLException
    // }
    
    // ПРАВИЛЬНО: throws или try-catch
    public void readFromDatabase() throws SQLException {
        Connection conn = java.sql.DriverManager.getConnection("...");
        // Теперь компилируется
    }
    
    // ПРАВИЛЬНО: try-catch
    public void readFromDatabaseSafe() {
        try {
            Connection conn = java.sql.DriverManager.getConnection("...");
        } catch (SQLException e) {
            System.err.println("Ошибка БД: " + e.getMessage());
        }
    }
}

5. Custom исключения

// Checked custom exception
public class InvalidUserException extends Exception {
    public InvalidUserException(String message) {
        super(message);
    }
    
    public InvalidUserException(String message, Throwable cause) {
        super(message, cause);
    }
}

// Unchecked custom exception
public class ValidationException extends RuntimeException {
    public ValidationException(String message) {
        super(message);
    }
}

// Использование
public class UserService {
    public void registerUser(String email) throws InvalidUserException {
        if (email == null || !email.contains("@")) {
            throw new InvalidUserException("Invalid email: " + email);
        }
    }
    
    public void validateAge(int age) {
        if (age < 0) {
            throw new ValidationException("Age cannot be negative");
        }
    }
}

6. Best Practices

public class ExceptionBestPractices {
    // ❌ ПЛОХО: Поймали, но ничего не сделали
    public void badHandler() {
        try {
            riskyOperation();
        } catch (IOException e) {
            // Молча проигнорировали ошибку!
        }
    }
    
    // ✅ ХОРОШО: Залогировали и обработали
    public void goodHandler() {
        try {
            riskyOperation();
        } catch (IOException e) {
            System.err.println("Операция не удалась: " + e.getMessage());
            // Или передали дальше
            throw new RuntimeException("Operation failed", e);
        }
    }
    
    // ✅ ЛУЧШЕ: Переброс как более специфичное исключение
    public void bestHandler() throws ApplicationException {
        try {
            riskyOperation();
        } catch (IOException e) {
            throw new ApplicationException("Failed to perform operation", e);
        }
    }
    
    // ✅ ИДЕАЛЬНО: try-with-resources + конкретная обработка
    public String readConfig(String path) throws ConfigException {
        try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
            return reader.readLine();
        } catch (FileNotFoundException e) {
            throw new ConfigException("Config file not found: " + path);
        } catch (IOException e) {
            throw new ConfigException("Failed to read config", e);
        }
    }
    
    private void riskyOperation() throws IOException {}
}

Главные выводы:

  • Checked exceptions — проверяются ВО ВРЕМЯ компиляции, код не скомпилируется без обработки
  • Unchecked exceptions — НЕ проверяются компилятором, но могут выброситься во время выполнения
  • throws — передаёт ответственность в вызывающий код
  • try-catch — обрабатывает исключение локально
  • try-with-resources — автоматически закрывает ресурсы

Правильная обработка исключений критична для надёжного и поддерживаемого кода.