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

Всегда ли исполняется finally?

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

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

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

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

Всегда ли исполняется finally блок?

Короткий ответ: почти всегда, но есть редкие исключения. Finally блок исполняется в подавляющем большинстве случаев, даже если в try или catch блоках возникли исключения. Но есть ситуации, когда это не происходит.

Когда finally ВЫПОЛНЯЕТСЯ

public class FinallyExecutionExamples {
    
    // Случай 1: Нормальное завершение try блока
    public static void example1() {
        try {
            System.out.println("Try block");
        } catch (Exception e) {
            System.out.println("Catch block");
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ
        }
    }
    
    // Случай 2: Исключение в try блоке
    public static void example2() {
        try {
            System.out.println("Try block");
            throw new RuntimeException("Error");
        } catch (RuntimeException e) {
            System.out.println("Catch block");
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ
        }
    }
    
    // Случай 3: Исключение в catch блоке
    public static void example3() {
        try {
            throw new RuntimeException("Error");
        } catch (RuntimeException e) {
            throw new IllegalArgumentException("New error");
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ перед выбросом
        }
    }
    
    // Случай 4: Return в try блоке
    public static int example4() {
        try {
            System.out.println("Try block");
            return 42;
        } catch (Exception e) {
            System.out.println("Catch block");
            return -1;
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ перед return
        }
    }
    
    // Случай 5: Continue/Break в try блоке
    public static void example5() {
        for (int i = 0; i < 3; i++) {
            try {
                if (i == 1) continue;  // Переход к следующей итерации
                System.out.println("Try: " + i);
            } finally {
                System.out.println("Finally: " + i);  // ✅ ВЫПОЛНИТСЯ
            }
        }
    }
    
    // Случай 6: System.exit() - НО ВЫПОЛНИТСЯ!
    public static void example6() {
        try {
            System.out.println("Try block");
            System.exit(0);  // Завершение программы
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ даже при exit!
        }
    }
}

Когда finally НЕ ВЫПОЛНЯЕТСЯ

public class FinallyNoExecutionExamples {
    
    // Случай 1: System.exit() с SecurityManager
    public static void example1() {
        try {
            System.out.println("Try block");
            System.exit(0);  // Полное завершение JVM
        } finally {
            System.out.println("Finally block");  // ❌ НЕ ВЫПОЛНИТСЯ
        }
    }
    
    // Случай 2: Бесконечный цикл в try блоке
    public static void example2() {
        try {
            while (true) {
                // Бесконечный цикл, никогда не закончится
            }
        } finally {
            System.out.println("Finally block");  // ❌ НЕ ВЫПОЛНИТСЯ
        }
    }
    
    // Случай 3: Убийство потока (Thread.stop() - deprecated)
    public static void example3() {
        try {
            System.out.println("Try block");
            Thread.currentThread().stop();  // Deprecated и опасно!
        } finally {
            System.out.println("Finally block");  // ❌ НЕ ВЫПОЛНИТСЯ
        }
    }
    
    // Случай 4: Критическая ошибка JVM (OutOfMemoryError при определенных условиях)
    public static void example4() {
        try {
            int[] array = new int[Integer.MAX_VALUE];  // OutOfMemoryError
        } finally {
            System.out.println("Finally block");  // ❌ Вероятно не выполнится
        }
    }
    
    // Случай 5: Отключение потока извне
    public static void example5() {
        try {
            System.out.println("Try block");
            Thread.sleep(Long.MAX_VALUE);  // Поток спит
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ!
        }
    }
}

Практический пример с возвращаемыми значениями

public class FinallyWithReturn {
    
    // Finally выполняется, но return значение из try имеет приоритет
    public static int example1() {
        int result = 10;
        try {
            System.out.println("Try block");
            return result;  // Запланировано возвратить 10
        } finally {
            System.out.println("Finally block");  // ✅ ВЫПОЛНИТСЯ
            result = 20;  // Изменение не повлияет на возвращаемое значение
        }
    }
    // Output:
    // Try block
    // Finally block
    // Возвращает: 10
    
    // Finally может изменить объект!
    public static String example2() {
        StringBuilder sb = new StringBuilder("Hello");
        try {
            return sb.toString();  // Возвращает "Hello"
        } finally {
            sb.append(" World");  // Изменяет объект (но return уже выполнен)
        }
    }
    // Возвращает: "Hello"
    
    // Finally может переопределить исключение!
    public static int example3() {
        try {
            throw new RuntimeException("Original exception");
        } finally {
            return 42;  // ⚠️ Подавляет исключение (плохая практика!)
        }
    }
    // Возвращает: 42 (исключение подавлено)
    
    // Finally может выбросить новое исключение!
    public static void example4() {
        try {
            throw new RuntimeException("Original exception");
        } finally {
            throw new IllegalArgumentException("New exception");
            // ⚠️ Новое исключение заменит исходное
        }
    }
    // Выбросит: IllegalArgumentException (RuntimeException потеряется)
}

Try-with-resources (Java 7+)

Это современный способ работы с ресурсами, более надежный чем finally:

public class TryWithResources {
    
    // До Java 7 (старый способ с finally)
    public static void oldWay() throws IOException {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("file.txt"));
            String line = reader.readLine();
        } finally {
            if (reader != null) {
                try {
                    reader.close();  // Нужно явно закрыть
                } catch (IOException e) {
                    // Нужно обработать исключение при закрытии
                }
            }
        }
    }
    
    // Java 7+ (try-with-resources)
    public static void newWay() throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
            String line = reader.readLine();
        }  // Reader закроется автоматически, даже если будет исключение
    }
    
    // Несколько ресурсов
    public static void multipleResources() throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader("input.txt")); 
             BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
            }
        }  // Оба ресурса закроются в обратном порядке
    }
}

Best Practices

public class BestPractices {
    
    // ❌ Плохо: finally переопределяет исключение
    public void bad() {
        try {
            throw new RuntimeException("Error");
        } finally {
            return;  // Исключение подавляется!
        }
    }
    
    // ✅ Хорошо: использовать try-with-resources для ресурсов
    public void good() throws IOException {
        try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
            String line = reader.readLine();
        }  // Автоматическое закрытие
    }
    
    // ✅ Хорошо: finally только для критичных операций
    public void cleanup() {
        Connection conn = null;
        try {
            conn = getConnection();
            // работа с подключением
        } catch (SQLException e) {
            logger.error("Database error", e);
        } finally {
            if (conn != null) {
                try {
                    conn.close();  // Критичная операция закрытия
                } catch (SQLException e) {
                    logger.error("Error closing connection", e);
                }
            }
        }
    }
}

Таблица исполнения finally

СитуацияFinallyПримечание
Нормальное завершение try✅ ДаСтандартный случай
Исключение в try✅ ДаВыполнится перед броском
Исключение в catch✅ ДаВыполнится перед броском
Return в try✅ ДаВыполнится перед return
Return в catch✅ ДаВыполнится перед return
Break/Continue✅ ДаВыполнится перед jump
System.exit()✅ ДаВыполнится перед exit
Бесконечный цикл❌ НетНикогда не завершится
Thread.stop()❌ НетDeprecated и опасно
OutOfMemoryError❌ НетКритичная ошибка JVM

Вывод

Finally выполняется почти всегда, но есть редкие исключения:

  1. Нормальные: Return, исключения, break, continue - finally выполнится
  2. Редкие: Бесконечный цикл, System.exit(), критичные ошибки JVM - finally не выполнится

Для современного кода используй try-with-resources вместо finally для управления ресурсами.

Всегда ли исполняется finally? | PrepBro