Всегда ли выполняется блок finally в конструкции try-catch-finally в Java?

«Всегда ли выполняется блок finally в конструкции try-catch-finally в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, блок finally выполняется не всегда. Хотя он предназначен для гарантированного выполнения кода очистки, существуют исключительные ситуации:

Когда finally НЕ выполнится:

  1. Принудительное завершение JVM: Вызов System.exit(int) в блоке try или catch.
  2. Прерывание потока: Если поток выполнения был прерван (например, Thread.stop() или Thread.interrupt() в определенных сценариях).
  3. Критическая ошибка JVM: Фатальные системные ошибки, такие как OutOfMemoryError или сбой нативного кода, который "убивает" процесс.
  4. Бесконечный цикл: Если код в блоке try или catch зацикливается и никогда не завершается.

Пример с System.exit():

try {
    System.out.println("Inside try block");
    System.exit(0); // Немедленное завершение JVM
} finally {
    // Этот код никогда не выполнится
    System.out.println("Inside finally block");
}

Практическое применение: В нормальных условиях finally выполняется вне зависимости от того, было выброшено исключение или нет. Это делает его идеальным местом для освобождения ресурсов: закрытия файловых потоков (FileInputStream), сетевых соединений или объектов Scanner.

try (Scanner scanner = new Scanner(new File("test.txt"))) {
    // Автоматическое управление ресурсами (try-with-resources) предпочтительнее
} catch (FileNotFoundException e) {
    e.printStackTrace();
}
// Для ресурсов, не поддерживающих AutoCloseable, используйте finally:
Scanner oldScanner = null;
try {
    oldScanner = new Scanner(new File("old.txt"));
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (oldScanner != null) {
        oldScanner.close(); // Гарантированное закрытие
    }
}