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

Проверяемой или непроверяемой ошибкой является StackOverflowError

1.0 Junior🔥 191 комментариев
#Soft Skills и карьера

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

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

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

Проверяемой или непроверяемой ошибкой является StackOverflowError

StackOverflowError — это непроверяемая ошибка (unchecked error), которая наследуется от класса Error, а не от Exception. Это важное различие определяет, как обрабатывать эту ошибку в Java-приложении.

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

Throwable
├── Exception (Checked exceptions)
│   ├── IOException
│   ├── SQLException
│   ├── FileNotFoundException
│   └── ...
│
└── Error (Unchecked errors) ← StackOverflowError
    ├── StackOverflowError
    ├── OutOfMemoryError
    ├── VirtualMachineError
    └── ...

Ключевое отличие:

// Checked Exception - ОБЯЗАТЕЛЬНО обрабатывать
public void readFile() throws IOException {  // Или try-catch
    FileReader reader = new FileReader("file.txt");
}

// Error (непроверяемая) - НЕ обязательно обрабатывать
public void recursiveMethod() {
    // StackOverflowError будет выброшена автоматически
    recursiveMethod();  // Бесконечная рекурсия
}

Почему StackOverflowError - это Error, а не Exception

1. Серьезность ошибки

Error используется для критических, непправляемых ситуаций, при которых приложение не может продолжать работу:

// StackOverflowError - не можно "исправить" во время выполнения
public class ProblematicCode {
    
    // ✗ Бесконечная рекурсия
    public void infiniteRecursion() {
        infiniteRecursion();  // Переполнит stack
        // StackOverflowError будет выброшена когда stack переполнится
    }
    
    // Эту ошибку нельзя "поймать" и исправить логически
    // Это признак ошибки в коде или данных
}

2. Отличие Exception и Error

Exception                           Error
────────────────────────────────────────────────
Ошибки в логике приложения         Критические сбои системы
Mожно обработать и continue         Приложение должно завершиться
Проверяемые (на некоторых)          Всегда непроверяемые
Примеры:                            Примеры:
- IOException                       - StackOverflowError
- SQLException                      - OutOfMemoryError
- NullPointerException              - VirtualMachineError

StackOverflowError на практике

Пример 1: Бесконечная рекурсия

public class StackOverflowDemo {
    
    // ✗ НЕПРАВИЛЬНО
    public int factorial(int n) {
        return n * factorial(n - 1);  // Никогда не останавливается!
    }
    
    public static void main(String[] args) {
        StackOverflowDemo demo = new StackOverflowDemo();
        System.out.println(demo.factorial(5));
        // Exception in thread "main" java.lang.StackOverflowError
        // at StackOverflowDemo.factorial(StackOverflowDemo.java:3)
        // at StackOverflowDemo.factorial(StackOverflowDemo.java:3)
        // ...(повторяется много раз)
    }
}

Пример 2: Взаимная рекурсия

public class MutualRecursion {
    
    public void methodA() {
        methodB();  // Вызывает B
    }
    
    public void methodB() {
        methodA();  // B вызывает A обратно
    }
    
    public static void main(String[] args) {
        MutualRecursion obj = new MutualRecursion();
        obj.methodA();  // StackOverflowError!
    }
}

Пример 3: Глубокая рекурсия при сериализации

public class Node {
    String value;
    Node next;
    
    @Override
    public String toString() {
        // ✗ ОПАСНО: toString может привести к глубокой рекурсии
        return value + " -> " + next.toString();
    }
}

public class Demo {
    public static void main(String[] args) {
        // Создаем длинный список
        Node head = new Node();
        head.value = "A";
        
        Node current = head;
        for (int i = 0; i < 100000; i++) {
            Node next = new Node();
            next.value = "Node" + i;
            current.next = next;
            current = next;
        }
        
        System.out.println(head);  // StackOverflowError из-за рекурсивного toString!
    }
}

Можно ли поймать StackOverflowError

Технически можно, но это не рекомендуется:

// ТЕХНИЧЕСКИ можно
try {
    recursiveMethod();
} catch (StackOverflowError e) {
    System.err.println("Stack переполнена!");
    e.printStackTrace();
}

// НО ПРОБЛЕМЫ:
// 1. После StackOverflowError, состояние JVM нестабильно
// 2. Невозможно безопасно продолжить работу
// 3. Catch блок сам может выбросить еще одну ошибку
// 4. Это маскирует реальную проблему в коде

Правильный подход: исправить код, а не ловить ошибку

// ✓ ПРАВИЛЬНО - исправить рекурсию
public int factorial(int n) {
    if (n <= 1) {
        return 1;  // Base case
    }
    return n * factorial(n - 1);  // Теперь остановится
}

Сравнение StackOverflowError с другими ошибками

StackOverflowError

// Стек переполнен (рекурсия, циклы вызовов)
try {
    infiniteRecursion();  // StackOverflowError - НЕЛЬЗЯ обработать
} catch (StackOverflowError e) {
    // Приложение в нестабильном состоянии
}

OutOfMemoryError

// Куча переполнена (слишком много объектов)
try {
    List<byte[]> list = new ArrayList<>();
    while (true) {
        list.add(new byte[1024 * 1024]);  // OutOfMemoryError
    }
} catch (OutOfMemoryError e) {
    // Также нельзя безопасно обработать
}

NullPointerException (RuntimeException)

// Ошибка в логике - можно обработать
try {
    String str = null;
    int length = str.length();  // NullPointerException
} catch (NullPointerException e) {
    // Можно обработать и продолжить
    System.out.println("String was null");
}

Различие: Checked vs Unchecked

// CHECKED Exception - компилятор ТРЕБУЕТ обработки
public void readFile() throws IOException {
    FileReader reader = new FileReader("file.txt");
}

// Вызывающий код ОБЯЗАН обработать
try {
    readFile();
} catch (IOException e) {
    System.err.println("Cannot read file");
}

// UNCHECKED Error/RuntimeException - компилятор не требует обработки
public void process() {
    int result = 10 / 0;  // ArithmeticException (unchecked)
    // Компилятор не требует try-catch
}

// Можно, но не обязательно, обрабатывать
try {
    process();
} catch (ArithmeticException e) {
    System.err.println("Invalid operation");
}

Stack Size и StackOverflowError

Размер стека можно изменить

# При запуске Java приложения можно задать размер стека
java -Xss1m MyApplication  # 1MB для каждого потока
java -Xss10m MyApplication  # 10MB для каждого потока

Но это не решает основную проблему — если стек переполняется, это значит что-то не так в коде.

Определение глубины рекурсии

public class RecursionDepth {
    
    private static int depth = 0;
    private static final int MAX_DEPTH = 10000;
    
    public void limitedRecursion() {
        depth++;
        
        if (depth > MAX_DEPTH) {
            throw new IllegalArgumentException(
                "Recursion depth exceeded: " + depth
            );
        }
        
        // Обработка
        // ...
        
        limitedRecursion();  // Безопаснее чем полагаться на StackOverflowError
        
        depth--;
    }
}

Best Practices

1. Избегать глубокой рекурсии

// ✗ РЕКУРСИЯ (может привести к StackOverflowError на больших данных)
public long sumList(List<Integer> list, int index) {
    if (index >= list.size()) return 0;
    return list.get(index) + sumList(list, index + 1);
}

// ✓ ИТЕРАЦИЯ (безопасно для любого размера списка)
public long sumList(List<Integer> list) {
    long sum = 0;
    for (int num : list) {
        sum += num;
    }
    return sum;
}

2. Tail Call Optimization (в некоторых языках, не в Java)

Java не оптимизирует tail-recursive вызовы, поэтому используйте итерацию.

3. Трамполин паттерн для рекурсии

// Если нужна рекурсия, используйте трамполин
public interface Trampoline<T> {
    T result();
    boolean isComplete();
}

public class TrampolineImpl<T> implements Trampoline<T> {
    private T value;
    public TrampolineImpl(T value) { this.value = value; }
    public T result() { return value; }
    public boolean isComplete() { return true; }
}

// Использование: избегает глубокого стека вызовов

Заключение

StackOverflowError — это непроверяемая ошибка (unchecked error), которая:

  • Наследуется от Error, а не Exception
  • Указывает на критическую проблему в коде (обычно глубокая рекурсия)
  • Не может быть корректно обработана во время выполнения
  • Не требует объявления в throws или обработки try-catch (компилятор не проверяет)
  • Указывает на необходимость исправить код, а не ловить ошибку

Запомните: если вы видите StackOverflowError, это признак того, что вам нужно переписать логику, а не обрабатывать ошибку.

Проверяемой или непроверяемой ошибкой является StackOverflowError | PrepBro