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

Какие Error невозможно отловить

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

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

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

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

Какие Error невозможно отловить

В Java существует различие между Exception и Error. Error'ы — это серьезные проблемы, которые обычно невозможно обработать. Рассмотрю, какие ошибки невозможно или нельзя ловить.

1. Error vs Exception иерархия

java.lang.Throwable (база для всех ошибок)
├── java.lang.Exception (обрабатываемые исключения)
│   ├── IOException
│   ├── SQLException
│   ├── RuntimeException (необработанные исключения)
│   │   ├── NullPointerException
│   │   ├── ArrayIndexOutOfBoundsException
│   │   └── ArithmeticException
│   └── (другие проверяемые исключения)
└── java.lang.Error (необработанные критичные ошибки)
    ├── OutOfMemoryError
    ├── StackOverflowError
    ├── VirtualMachineError
    ├── ThreadDeath
    └── (другие критичные ошибки)

2. Error'ы, которые нельзя обработать

OutOfMemoryError (Нехватка памяти)

// Эта ошибка НИКОГДА не должна обрабатываться
// Потому что нет памяти даже для обработки исключения!

public class OutOfMemoryExample {
    public static void main(String[] args) {
        try {
            // Пытаемся создать огромный массив
            int[] huge = new int[Integer.MAX_VALUE];
        } catch (OutOfMemoryError e) {
            // ❌ НИКОГДА так не делай!
            // Нет памяти для обработки, попытка вывода может завершить JVM
            System.out.println("Out of memory!");
        }
    }
}

// Правильный подход — предотвращение
public class MemorySafeExample {
    public static void main(String[] args) {
        // 1. Используй -Xmx для ограничения памяти
        // java -Xmx512m MyApp
        
        // 2. Обрабатывай исключения, которые могут привести к OutOfMemory
        try {
            List<String> list = new ArrayList<>();
            for (int i = 0; i < 1_000_000_000; i++) {
                list.add("item " + i);
                // Может бросить OutOfMemoryError
            }
        } catch (Exception e) {
            // Обрабатываем предосторожностью
            logger.error("Error during processing", e);
        }
        
        // 3. Мониторь использование памяти
        Runtime runtime = Runtime.getRuntime();
        long usedMemory = runtime.totalMemory() - runtime.freeMemory();
        if (usedMemory > runtime.maxMemory() * 0.9) {
            logger.warn("Memory usage is above 90%");
            // Очисти кеши, освободи ресурсы
        }
    }
}

StackOverflowError (Переполнение стека)

// Бесконечная рекурсия вызовет StackOverflowError
public class StackOverflowExample {
    // ❌ НЕПРАВИЛЬНО: бесконечная рекурсия
    public void recursiveMethodBad() {
        recursiveMethodBad();  // Вызывает сама себя
    }
    
    // ❌ Попытка обработать StackOverflowError бесполезна
    public static void main(String[] args) {
        try {
            new StackOverflowExample().recursiveMethodBad();
        } catch (StackOverflowError e) {
            // Стек переполнен, эта ловушка может не сработать!
            System.out.println("Stack overflow!");
        }
    }
}

// ✅ ПРАВИЛЬНО: рекурсия с базовым случаем
public class StackOverflowFixed {
    public int factorial(int n) {
        if (n <= 1) {
            return 1;  // Базовый случай — выход из рекурсии
        }
        return n * factorial(n - 1);  // Рекурсивный вызов
    }
    
    // Альтернатива: итерация вместо рекурсии
    public int factorialIterative(int n) {
        int result = 1;
        for (int i = 2; i <= n; i++) {
            result *= i;
        }
        return result;
    }
}

VirtualMachineError (Ошибки JVM)

// Включает InternalError, OutOfMemoryError, StackOverflowError
// Это критичные ошибки, которые означают, что JVM не работает правильно

public class VirtualMachineErrorExample {
    public static void main(String[] args) {
        try {
            // Внутренняя ошибка JVM
            // Может быть вызвана ошибкой в самой JVM
        } catch (VirtualMachineError e) {
            // ❌ Не обрабатывай — это означает, что JVM сломана
            // Лучше перезагрузить приложение/сервер
            System.exit(1);
        }
    }
}

ThreadDeath (Завершение потока)

// Deprecated, но все еще существует
public class ThreadDeathExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        });
        
        // ❌ НИКОГДА не используй stop() — он вызывает ThreadDeath
        // thread.stop();  // Deprecated!
        
        // ✅ ПРАВИЛЬНО: используй interrupt()
        // thread.interrupt();
    }
}

3. AssertionError (Ошибки утверждений)

// AssertionError выбрасывается при нарушении assert
public class AssertionErrorExample {
    public static void main(String[] args) {
        int age = -5;
        
        // Ловушка для ошибок утверждений
        try {
            assert age >= 0 : "Age cannot be negative";
        } catch (AssertionError e) {
            // Технически можно поймать, но это плохая практика
            System.out.println("Assertion failed: " + e.getMessage());
        }
    }
}

// ✅ ЛУЧШЕ: предотвращение
public class AssertionErrorFixed {
    public void setAge(int age) {
        if (age < 0) {
            throw new IllegalArgumentException("Age cannot be negative");
        }
        this.age = age;
    }
}

4. Какие ошибки МОЖНО обработать

// ✅ RuntimeException — можно обработать
public class RuntimeExceptionExample {
    public static void main(String[] args) {
        try {
            int result = 10 / 0;  // ArithmeticException
        } catch (ArithmeticException e) {
            System.out.println("Cannot divide by zero");
        }
        
        try {
            String str = null;
            str.length();  // NullPointerException
        } catch (NullPointerException e) {
            System.out.println("Null pointer!");
        }
        
        try {
            int[] arr = {1, 2, 3};
            int value = arr[10];  // ArrayIndexOutOfBoundsException
        } catch (IndexOutOfBoundsException e) {
            System.out.println("Array index out of bounds");
        }
    }
}

// ✅ Checked Exception — ОБЯЗАТЕЛЬНО обработать
public class CheckedExceptionExample {
    public static void main(String[] args) {
        try {
            // IOException — checked exception, обязательно обработать
            FileReader reader = new FileReader("file.txt");
            int ch = reader.read();
            reader.close();
        } catch (FileNotFoundException e) {
            System.out.println("File not found: " + e.getMessage());
        } catch (IOException e) {
            System.out.println("IO error: " + e.getMessage());
        }
    }
}

5. UncaughtExceptionHandler (Глобальная обработка)

// Для ошибок, которые не были обработаны
public class GlobalExceptionHandler {
    public static void main(String[] args) {
        // Установить глобальный обработчик для потоков
        Thread.setDefaultUncaughtExceptionHandler((thread, throwable) -> {
            logger.error("Uncaught exception in thread: " + thread.getName(), throwable);
            
            // Если это ошибка, а не исключение
            if (throwable instanceof Error) {
                logger.error("CRITICAL ERROR - shutting down", throwable);
                // Graceful shutdown
                System.exit(1);
            }
        });
        
        // Для отдельного потока
        Thread thread = new Thread(() -> {
            throw new RuntimeException("Error in thread");
        });
        
        thread.setUncaughtExceptionHandler((t, e) -> {
            logger.error("Thread exception", e);
        });
        
        thread.start();
    }
}

6. Spring Boot глобальная обработка

// Global Exception Handler в Spring
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    // Обработка проверяемых исключений
    @ExceptionHandler(FileNotFoundException.class)
    public ResponseEntity<ErrorResponse> handleFileNotFound(FileNotFoundException e) {
        return ResponseEntity.status(HttpStatus.NOT_FOUND)
            .body(new ErrorResponse("FILE_NOT_FOUND", e.getMessage()));
    }
    
    // Обработка runtime исключений
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<ErrorResponse> handleIllegalArgument(IllegalArgumentException e) {
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
            .body(new ErrorResponse("INVALID_ARGUMENT", e.getMessage()));
    }
    
    // НЕ ОБРАБАТЫВАЙ Error'ы здесь!
    // OutOfMemoryError, StackOverflowError не попадут сюда
    // и обработаны не будут
    
    @ExceptionHandler(Exception.class)
    public ResponseEntity<ErrorResponse> handleGenericException(Exception e) {
        logger.error("Unexpected error", e);
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
            .body(new ErrorResponse("INTERNAL_ERROR", "Internal server error"));
    }
}

Чеклист: что можно/нельзя обработать

ТипПримерМожно ловить?Нужно ловить?
Checked ExceptionIOException, SQLException✅ Да✅ Да (обязательно)
RuntimeExceptionNPE, ArithmeticException✅ Да🔶 Лучше предотвращать
OutOfMemoryError❌ Нет (или бесполезно)❌ Нет❌ Нет (перезагрузить)
StackOverflowError❌ Нет❌ Нет❌ Нет (исправить рекурсию)
VirtualMachineError❌ Нет❌ Нет❌ Нет (перезагрузить JVM)
ThreadDeath❌ Deprecated❌ Нет❌ Нет (использовать interrupt)

Лучшие практики

  1. Не ловай Error'ы — это означает, что JVM сломана
  2. Предотвращай ошибки — проверяй null, размеры массивов
  3. Ловай только нужные исключения — не catch (Exception e)
  4. Логируй все ошибки — для отладки
  5. Gracefully shutdown при Error'ах — лучше перезагрузить
  6. Мониторь OutOfMemoryError — используй инструменты мониторинга
  7. Исправляй StackOverflowError — переписи рекурсию на итерацию

Итог: Error'ы (OutOfMemory, StackOverflow, VirtualMachineError) невозможно и нельзя обрабатывать. Их лучше предотвращать и gracefully перезагружать приложение.

Какие Error невозможно отловить | PrepBro