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

Почему не нужно отлавливать Error?

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

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

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

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

Почему не нужно отлавливать Error?

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

В Java все исключения наследуются от класса Throwable, который разделяется на три основные категории:

Throwable
├── Exception (должны обрабатываться приложением)
│   ├── IOException
│   ├── SQLException
│   └── CustomCheckedException
└── Error (системные ошибки, НЕ должны обрабатываться)
    ├── OutOfMemoryError
    ├── StackOverflowError
    └── VirtualMachineError

Основные причины не отлавливать Error

1. Error указывает на неисправимые состояния JVM

Ошибки типа Error возникают в ситуациях, когда приложение находится в критическом состоянии и восстановление невозможно:

// ❌ ПЛОХО - никогда так не делай
try {
    // код с рекурсией
    processData(data);
} catch (StackOverflowError e) {
    // невозможно восстановиться после переполнения стека
    System.out.println("Ошибка!");
}

// ✅ ХОРОШО - избегай проблемы в корне
// Используй итерацию вместо рекурсии
public void processIteratively(List<Data> data) {
    for (Data item : data) {
        processItem(item);
    }
}

2. Error означает проблему вне контроля приложения

OutOfMemoryError возникает, когда JVM не может выделить больше памяти. Обработка этой ошибки бесполезна, так как нет свободных ресурсов:

// ❌ НЕПРАВИЛЬНО
try {
    byte[] data = new byte[Integer.MAX_VALUE];
} catch (OutOfMemoryError e) {
    // нечего делать - память исчерпана
    logger.error("Out of memory");
}

3. Error нарушает контракт проверяемых исключений

Если ты обрабатываешь Error, ты нарушаешь соглашение, что checked exceptions (IOException, SQLException) требуют обработки, а системные ошибки — нет:

public void readFile(String path) throws IOException {
    // IOException - проверяемое, ДОЛЖНО обрабатываться
    FileReader reader = new FileReader(path);
    
    // OutOfMemoryError - неконтролируемая системная ошибка
    // Её не нужно перехватывать здесь
}

Что можно сделать вместо обработки Error

1. Логирование на высоком уровне

public class UncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        if (e instanceof Error) {
            // Логируем критическую ошибку
            logger.fatal("JVM Error in thread " + t.getName(), e);
            // Корректно завершаем приложение
            System.exit(1);
        }
    }
}

2. Профилактика проблем

public class MemoryMonitor {
    private static final long THRESHOLD = Runtime.getRuntime().maxMemory() * 80 / 100;
    
    public static void checkMemory() {
        long used = Runtime.getRuntime().totalMemory() 
                    - Runtime.getRuntime().freeMemory();
        
        if (used > THRESHOLD) {
            // Заранее освобождаем ресурсы
            System.gc();
            // Или выбрасываем checked exception
            throw new LowMemoryException("Memory usage " + used);
        }
    }
}

Когда Exception вместо Error

public class DataProcessor {
    // ✅ ПРАВИЛЬНО - обрабатываем предсказуемые ошибки
    public void process(String filePath) throws IOException {
        if (Files.notExists(Paths.get(filePath))) {
            throw new FileNotFoundException("File not found");
        }
        
        try (BufferedReader reader = new BufferedReader(
                new FileReader(filePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                parseLine(line); // может выбросить ParseException
            }
        } catch (IOException e) {
            logger.error("Failed to read file", e);
            throw e; // Пробрасываем выше
        }
    }
}

Резюме

  • Error = системная проблема JVM, обработка невозможна
  • Exception = бизнес-ошибка, должна обрабатываться
  • Не отлавливай Error, предотвращай проблемы проектированием
  • Используй UncaughtExceptionHandler для логирования критических ошибок на уровне приложения