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

Наследуется ли RuntimeException от Exception

1.3 Junior🔥 51 комментариев
#Основы Java

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

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

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

Иерархия исключений: RuntimeException и Exception

Ответ: да, RuntimeException наследуется от Exception, но это создаёт интересную ситуацию в Java. Давайте разберёмся в деталях.

Иерархия классов в Java

// Полная иерархия исключений в Java:

Throwable
├── Exception
│   ├── RuntimeException
│   │   ├── NullPointerException
│   │   ├── ArithmeticException
│   │   ├── ArrayIndexOutOfBoundsException
│   │   └── ...
│   ├── IOException
│   ├── SQLException
│   ├── ClassNotFoundException
│   └── ... (Checked exceptions)
└── Error
    ├── OutOfMemoryError
    ├── StackOverflowError
    └── ... (серьёзные ошибки системы)

RuntimeException наследуется от Exception:

public class RuntimeException extends Exception {
    // ...
}

Exception наследуется от Throwable:

public class Exception extends Throwable {
    // ...
}

Иерархия выглядит так:

Throwable
    ↓
Exception  ← RuntimeException наследуется отсюда
    ↓
RuntimeException
    ↓
NullPointerException (например)

Разница: Checked vs Unchecked

Хотя RuntimeException наследуется от Exception, они обрабатываются по-разному компилятором:

1. Checked Exception (Исключения, которые проверяет компилятор)

// ✅ Обычные Exception (не Runtime)
public void readFile() throws IOException {  // ОБЯЗАТЕЛЬНО throws!
    // Если не обработаем, компилятор выкинет ошибку
    FileInputStream fis = new FileInputStream("file.txt");
    // ...
}

// Вызывающий код ДОЛЖЕН обработать или пробросить
public void doSomething() throws IOException {  // throws
    readFile();  // Должны указать, что можем выкинуть IOException
}

// Или обработать в try-catch
public void doSomethingElse() {
    try {
        readFile();
    } catch (IOException e) {  // ОБЯЗАТЕЛЬНО catch
        e.printStackTrace();
    }
}

2. Unchecked Exception (RuntimeException)

// ❌ RuntimeException - компилятор НЕ проверяет
public void divideNumbers(int a, int b) {
    // НЕ нужно throws!
    int result = a / b;  // Может выкинуть ArithmeticException
    // НЕ нужно try-catch!
}

// Можно вызвать без обработки
public void main(String[] args) {
    divideNumbers(10, 0);  // Без try-catch, без throws
    // Если b = 0, выкинет ArithmeticException (подтип RuntimeException)
}

// Но можно обработать, если хотим
public void main(String[] args) {
    try {
        divideNumbers(10, 0);
    } catch (ArithmeticException e) {  // Опционально
        System.out.println("Division by zero!");
    }
}

Разница в использовании

// ✅ Checked Exception - IOException (наследуется от Exception, но НЕ от RuntimeException)
public void readFile(String path) throws IOException {
    // IOException ДОЛЖНО быть обработано
    FileInputStream fis = new FileInputStream(path);
}

// ❌ Unchecked Exception - RuntimeException и подклассы
public void getValue(List<String> list, int index) {
    // IndexOutOfBoundsException (подтип RuntimeException) не нужно объявлять
    String value = list.get(index);  // Может выкинуть IndexOutOfBoundsException
}

// Сравнение сигнатур:
// throws IOException         <- Checked Exception
// throws RuntimeException    <- Unchecked (но технически можем указать)

Почему нужны оба типа?

Checked Exception (IOException, SQLException)

// Используется для ожидаемых, восстанавливаемых ошибок:

public void saveToDatabase(User user) throws SQLException {
    // SQLException - может случиться при отключении БД
    // Разработчик должен обработать и, например, сделать retry
    // Это ожидаемое исключение
}

// Вызывающий код ОБЯЗАН обработать
public void registerUser(User user) throws SQLException {
    // throws - пробрасываем выше
    // или
    try {
        saveToDatabase(user);
    } catch (SQLException e) {
        // Обрабатываем: retry, fallback, логирование
    }
}

Unchecked Exception (RuntimeException)

// Используется для непредвиденных, невосстанавливаемых ошибок:

public int divide(int a, int b) {
    // ArithmeticException - ошибка разработчика (деление на 0)
    // Это ДОЛЖНА быть исправлена в коде, не обработана в runtime
    return a / b;  // Может выкинуть ArithmeticException
}

// Вызывающий не ОБЯЗАН обрабатывать
public void calculate() {
    int result = divide(10, 0);  // Программа упадёт, если b = 0
    // Но это ошибка разработчика, не runtime проблема
}

Практический пример: разница во время разработки

// ❌ Checked Exception - компилятор не даст скомпилировать без обработки
public void badCode1() {
    new FileInputStream("file.txt");  // ОШИБКА КОМПИЛЯЦИИ!
    // error: unreported exception FileNotFoundException
    // Нужно либо throws, либо try-catch
}

// ✅ RuntimeException - компилятор позволит
public void badCode2() {
    int[] array = new int[5];
    System.out.println(array[10]);  // Компилируется!
    // Но в runtime выкинет ArrayIndexOutOfBoundsException
}

Иерархия в коде

// ✅ Доказательство, что RuntimeException extends Exception

RuntimeException ex = new NullPointerException("test");

// Можно присвоить Exception
Exception e = ex;  // OK, потому что RuntimeException extends Exception

// Можно присвоить Throwable
Throwable t = ex;  // OK

// instanceof работает везде
if (ex instanceof Exception) {
    System.out.println("RuntimeException является Exception");  // true
}

if (ex instanceof RuntimeException) {
    System.out.println("NullPointerException является RuntimeException");  // true
}

if (ex instanceof Throwable) {
    System.out.println("Всё является Throwable");  // true
}

Catchblock для обоих типов

// ✅ Можно ловить RuntimeException как Exception
public void handleException() {
    try {
        Integer.parseInt("not a number");  // Throws NumberFormatException (RuntimeException)
    } catch (Exception e) {  // Можно ловить как Exception
        System.out.println("Caught: " + e);
    }
}

// Разница: что нужно ловить
public void readAndParse(String filePath) {
    try {
        String content = readFile(filePath);  // Throws IOException (checked)
        Integer.parseInt(content);             // Throws NumberFormatException (unchecked)
    } catch (IOException e) {  // ОБЯЗАТЕЛЬНО ловим checked
        System.out.println("File error: " + e);
    } catch (NumberFormatException e) {  // ОПЦИОНАЛЬНО ловим unchecked
        System.out.println("Parse error: " + e);
    }
}

Создание собственных исключений

// ❌ Собственное Checked Exception
public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

// Использование:
public void withdraw(BigDecimal amount) throws InsufficientFundsException {
    if (balance.compareTo(amount) < 0) {
        throw new InsufficientFundsException("Not enough funds");
    }
    balance = balance.subtract(amount);
}

// Вызывающий ОБЯЗАН обработать
public void processWithdrawal(BigDecimal amount) {
    try {
        withdraw(amount);
    } catch (InsufficientFundsException e) {
        System.out.println("Cannot withdraw: " + e.getMessage());
    }
}

// ✅ Собственное Unchecked Exception
public class InvalidAccountException extends RuntimeException {
    public InvalidAccountException(String message) {
        super(message);
    }
}

// Использование:
public void validateAccount(String accountNumber) {
    if (accountNumber == null || accountNumber.isEmpty()) {
        throw new InvalidAccountException("Invalid account number");
    }
}

// Вызывающий НЕ обязан обрабатывать
public void transferMoney(String fromAccount, String toAccount) {
    // Без try-catch
    validateAccount(fromAccount);   // Может выкинуть, но не обязан обрабатывать
    validateAccount(toAccount);
}

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

АспектException (checked)RuntimeException (unchecked)
НаследованиеThrowable → ExceptionThrowable → Exception → RuntimeException
Проверка компилятором✅ Обязательна обработка❌ Не проверяется
throws✅ Обязателен в сигнатуре❌ Опционален
catch✅ Обязателен❌ Опционален
ПримерыIOException, SQLExceptionNullPointerException, ArrayIndexOutOfBoundsException
Когда использоватьОжидаемые ошибки (восстанавливаемые)Ошибки разработчика (программные)

Практические выводы

RuntimeException наследуется от Exception - это факт ✅ RuntimeException наследуется от Exception, но обрабатывается иначе ❌ RuntimeException НЕ проверяется компилятором (unchecked) ✅ Exception, которая НЕ RuntimeException, всегда checked ⚠️ Правило: используй Checked Exception для ожидаемых ошибок, Unchecked для ошибок разработчика

Ответ на интервью: "Да, RuntimeException наследуется от Exception, и мы можем видеть это в иерархии: Throwable → Exception → RuntimeException. Однако компилятор обрабатывает их по-разному: checked Exception (НЕ RuntimeException) обязательно должны быть обработаны или указаны в throws, в то время как unchecked RuntimeException этого не требуют. Checked Exception используются для ожидаемых, восстанавливаемых ошибок (например, IOException), а RuntimeException — для ошибок разработчика (например, NullPointerException)."

Наследуется ли RuntimeException от Exception | PrepBro