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

Какой главный интерфейс исключений?

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

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

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

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

Главный интерфейс исключений в Java

Вопрос о иерархии исключений - это фундаментальное знание для Java разработчика. В Java иерархия исключений очень чётко организована, и понимание её структуры критично для правильной обработки ошибок.

Главный интерфейс: Throwable

Throwable - это главный класс (по сути, базовый класс) для всех объектов, которые могут быть выброшены и перехвачены в Java. Это не совсем интерфейс, но это родитель всей иерархии.

Throwable (главный класс)
├── Exception (проверяемые исключения)
│   ├── IOException
│   ├── SQLException
│   ├── ClassNotFoundException
│   └── CustomException (пользовательские)
├── RuntimeException (непроверяемые исключения)
│   ├── NullPointerException
│   ├── ArrayIndexOutOfBoundsException
│   ├── IllegalArgumentException
│   └── CustomRuntimeException (пользовательские)
└── Error (критические ошибки)
    ├── OutOfMemoryError
    ├── StackOverflowError
    └── VirtualMachineError

Throwable класс

Throwable - это абстрактный класс, который все исключения в Java должны наследовать:

public class Throwable implements Serializable {
    // Основные методы
    public String getMessage()  // Получить сообщение об ошибке
    public void printStackTrace()  // Вывести stack trace
    public StackTraceElement[] getStackTrace()  // Получить стек вызовов
    public Throwable getCause()  // Получить причину исключения (chain)
    public Throwable initCause(Throwable cause)  // Установить причину
    public String toString()  // Получить текстовое представление
}

Иерархия Exception

Exception - это родительский класс для всех проверяемых исключений. Они ДОЛЖНЫ быть обработаны или объявлены в throws.

// Exception - проверяемое исключение
public class Exception extends Throwable {
    // Конструкторы
    public Exception()  // Без сообщения
    public Exception(String message)  // С сообщением
    public Exception(String message, Throwable cause)  // С причиной
    public Exception(Throwable cause)  // Только причина
}

Примеры встроенных checked exceptions:

// IOException - ошибки ввода-вывода
try {
    FileReader reader = new FileReader("file.txt");
} catch (FileNotFoundException e) {  // Проверяемое исключение
    System.out.println("Файл не найден: " + e.getMessage());
}

// SQLException - ошибки БД
try {
    Connection conn = DriverManager.getConnection("jdbc:mysql://localhost");
} catch (SQLException e) {  // Проверяемое исключение
    System.out.println("Ошибка БД: " + e.getMessage());
}

// ClassNotFoundException - класс не найден
try {
    Class.forName("com.example.NonExistentClass");
} catch (ClassNotFoundException e) {  // Проверяемое исключение
    System.out.println("Класс не найден: " + e.getMessage());
}

RuntimeException - непроверяемые исключения

RuntimeException - это исключения, которые НЕ обязательно обрабатывать. Они наследуют Exception, но могут быть выброшены в любой момент.

public class RuntimeException extends Exception {
    // Те же конструкторы, что и Exception
}

Примеры встроенных unchecked exceptions:

// NullPointerException - самое частое
String str = null;
int length = str.length();  // Выбросит NullPointerException

// ArrayIndexOutOfBoundsException - выход за границы
int[] array = new int[5];
int value = array[10];  // Выбросит ArrayIndexOutOfBoundsException

// IllegalArgumentException - неправильный аргумент
if (age < 0) {
    throw new IllegalArgumentException("Возраст не может быть отрицательным");
}

// ClassCastException - неправильный cast
Object obj = "string";
Integer number = (Integer) obj;  // Выбросит ClassCastException

Error - критические ошибки

Error - это для критических ошибок, которые не следует перехватывать. Это проблемы JVM, а не приложения.

// OutOfMemoryError - нет памяти
List<byte[]> list = new ArrayList<>();
while (true) {
    list.add(new byte[1024 * 1024]);  // Выбросит OutOfMemoryError
}

// StackOverflowError - переполнение стека
public void recursion() {
    recursion();  // Бесконечная рекурсия → StackOverflowError
}

Пользовательские исключения

В реальных проектах я создаю свои исключения для специфичных ошибок:

// Checked исключение - для expected ошибок
public class BusinessRuleException extends Exception {
    private final String errorCode;
    
    public BusinessRuleException(String message, String errorCode) {
        super(message);
        this.errorCode = errorCode;
    }
    
    public String getErrorCode() {
        return errorCode;
    }
}

// Unchecked исключение - для unexpected ошибок
public class InternalServerException extends RuntimeException {
    private final int statusCode;
    
    public InternalServerException(String message, int statusCode) {
        super(message);
        this.statusCode = statusCode;
    }
    
    public int getStatusCode() {
        return statusCode;
    }
}

// Использование
try {
    validateUser(user);  // Может выбросить BusinessRuleException
} catch (BusinessRuleException e) {
    logger.warn("Business rule violation: " + e.getMessage());
    return ResponseEntity.badRequest().body(e.getMessage());
}

Exception Chaining (цепочка исключений)

Важный паттерн - сохранение оригинальной причины ошибки:

try {
    // Операция с БД
    executeQuery(sql);
} catch (SQLException e) {
    // Обернуть в custom исключение, сохраняя оригинальную причину
    throw new DataAccessException("Ошибка при доступе к данным", e);
}

// Затем можно получить оригинальную причину
try {
    // ...
} catch (DataAccessException e) {
    Throwable cause = e.getCause();  // Получить SQLException
    logger.error("Root cause: " + cause.getMessage());
}

Правильная обработка исключений

public class ExceptionHandlingExample {
    
    // Правильно: catching more specific exceptions first
    public void processFile(String filename) {
        try {
            FileReader reader = new FileReader(filename);
            // ...
        } catch (FileNotFoundException e) {  // Специфичное исключение
            logger.error("File not found: " + filename, e);
            // Обработка специфичной ошибки
        } catch (IOException e) {  // Более общее исключение
            logger.error("IO error: " + e.getMessage(), e);
            // Обработка общей ошибки
        } catch (Exception e) {  // Самое общее исключение
            logger.error("Unexpected error", e);
            // Обработка неожиданной ошибки
        }
    }
    
    // Java 7+ - try-with-resources
    public void processFileModern(String filename) throws IOException {
        try (FileReader reader = new FileReader(filename)) {  // Auto-close
            // reader автоматически закроется
        } catch (FileNotFoundException e) {
            logger.error("File not found", e);
        }
    }
}

Мой подход в production

В реальных проектах я следую этим принципам:

  1. Используй checked exceptions для expected ошибок:

    • Ошибки БД, файловой системы, сети
  2. Используй unchecked exceptions для unexpected:

    • Programming errors, configuration issues
  3. Всегда логируй исключения:

    • С полным stack trace для отладки
  4. Сохраняй цепочку исключений:

    • throw new CustomException(msg, originalException)
  5. Не подавляй исключения молча:

    // ПЛОХО
    try { ... } catch (Exception e) { }  // Игнорируем!
    
    // ХОРОШО
    try { ... } catch (Exception e) {
        logger.error("Error occurred", e);
        throw new RuntimeException(e);
    }
    

Итог: Throwable - главный класс в иерархии исключений Java. Он имеет две ветки: Exception (для проверяемых ошибок) и Error (для критических ошибок). RuntimeException расширяет Exception для непроверяемых ошибок.