Является ли блок finally всегда исполняемым на Java?

Учитывая этот код, могу ли я быть абсолютно уверен, что блок finally всегда выполняется, вне зависимости от того, что something()?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("i don't know if this will get printed out.");
}
+2059
15 сент. '08 в 17:43
источник поделиться
30 ответов
  • 1
  • 2

Да, finally, вызывается после выполнения блоков try или catch.

Единственными моментами, которые, finally, не будут называться, являются:

  1. Если вы вызываете System.exit();
  2. Если сначала произойдет сбой JVM;
  3. Если JVM достигает бесконечного цикла (или другого не прерывающегося, не заканчивающегося оператора) в блоке try или catch;
  4. Если ОС принудительно завершает процесс JVM; например, "убить -9" в UNIX.
  5. Если хост-система умирает; например, сбой питания, аппаратная ошибка, паника ОС и т.д.
  6. Если, наконец, блок будет выполняться потоком демона, а все остальные не-демонные потоки выходят до того, как, наконец, вызывается.
+2297
15 сент. '08 в 17:45
источник

Пример кода:

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int test() {
    try {
        return 0;
    }
    finally {
        System.out.println("finally trumps return.");
    }
}

Вывод:

finally trumps return. 
0
+484
15 сент. '08 в 17:59
источник

Кроме того, хотя это плохая практика, если в блоке finally есть оператор return, он будет превзойти любой другой возврат из обычного блока. То есть, следующий блок вернет false:

try { return true; } finally { return false; }

То же самое, что бросает исключения из блока finally.

+345
15 сент. '08 в 18:19
источник

Вот официальные слова из спецификации языка Java.

14.20.2. Выполнение try-finally и try-catch-finally

Оператор try с блоком finally выполняется, сначала выполнив блок try. Тогда есть выбор:

  • Если выполнение блока try завершается нормально, [...]
  • Если выполнение блока try завершается внезапно из-за throw значения V, [...]
  • Если выполнение блока try завершается внезапно по любой другой причине R, выполняется блок finally. Тогда есть выбор:
    • Если блок finally завершается нормально, то оператор try завершается внезапно по причине R.
    • Если блок finally завершается внезапно для разума S, то оператор try совершает внезапно по причине S (и причина R отбрасывается).

Спецификация для return действительно делает это явным:

JLS 14.17 Оператор возврата

ReturnStatement:
     return Expression(opt) ;

A return без Expression пытается передать управление вызывающему методу или конструктору, который его содержит.

A return с помощью Expression попыток передать управление вызывающему методу, который содержит его; значение Expression становится значением вызова метода.

В предыдущих описаниях говорится, что " пытается передать управление", а не просто "передает управление", потому что, если в методе или конструкторе есть какие-либо try -операторы, чьи блоки try содержат return, то любые предложения finally этих операторов try будут выполняться, чтобы быть наиболее внутренним до внешнего, до того как управление будет передано вызову метода или конструктора. Резкое завершение предложения finally может нарушить передачу управления, инициированного оператором return.

+241
25 мая '10 в 6:50
источник

В дополнение к другим ответам важно указать, что "finally" имеет право переопределить любое исключение/возвращаемое значение блоком try..catch. Например, следующий код возвращает 12:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

Аналогично, следующий метод не генерирует исключения:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

В то время как следующий метод делает это:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}
+144
13 мая '10 в 7:11
источник

Я попробовал приведенный выше пример с небольшой модификацией -

public static void main(final String[] args) {
    System.out.println(test());
}

public static int test() {
    int i = 0;
    try {
        i = 2;
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
    }
}

Вышеупомянутый код выводит:

наконец, возвращает козыри.
2

Это происходит потому, что при выполнении return i; i имеет значение 2. После этого выполняется блок finally, где 12 назначается i, а затем выполняется System.out out.

После выполнения блока finally блок try возвращает 2, а не возвращает 12, потому что этот оператор возврата не выполняется снова.

Если вы отлаживаете этот код в Eclipse, вы почувствуете, что после выполнения System.out of finally блокирует оператор return блока try выполняется снова. Но это не так. Он просто возвращает значение 2.

+99
17 нояб. '08 в 16:25
источник

Вот разработка ответа Кевина. Важно знать, что возвращаемое выражение оценивается до finally, даже если оно возвращается после.

public static void main(String[] args) {
    System.out.println(Test.test());
}

public static int printX() {
    System.out.println("X");
    return 0;
}

public static int test() {
    try {
        return printX();
    }
    finally {
        System.out.println("finally trumps return... sort of");
    }
}

Вывод:

X
finally trumps return... sort of
0
+92
03 дек. '13 в 23:36
источник

Вот и вся идея окончательного блока. Он позволяет вам убедиться, что вы выполняете очистку, которая в противном случае может быть пропущена, потому что вы, конечно же, возвращаетесь, между прочим.

Наконец, вызывается независимо от того, что происходит в блоке try (если вы не вызываете System.exit(int) или виртуальная машина Java не запускается по какой-либо другой причине).

+49
13 мая '10 в 6:19
источник

Логический способ подумать об этом:

  • Код, помещенный в блок finally, должен быть выполнен независимо от того, что происходит в блоке try
  • Итак, если код в блоке try пытается вернуть значение или выбросить исключение, элемент будет помещен "на полку" до тех пор, пока блок finally не сможет выполнить
  • Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или бросать все, что ему нравится. В этом случае все, что осталось на полке, отбрасывается.
  • Единственным исключением из этого является то, что VM полностью отключается во время блока try, например. по 'System.exit'
+36
15 сент. '08 в 19:26
источник

Также возвращение в итоге выкинет любое исключение. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html

+18
15 сент. '08 в 19:26
источник

наконец, всегда выполняется, если нет ненормального завершения программы (например, вызов System.exit(0)..). поэтому ваш sysout будет напечатан

+17
15 сент. '08 в 17:46
источник

Нет, не всегда один случай исключения //System.exit(0); прежде чем блок finally предотвратит, наконец, выполнение.

  class A {
    public static void main(String args[]){
        DataInputStream cin = new DataInputStream(System.in);
        try{
            int i=Integer.parseInt(cin.readLine());
        }catch(ArithmeticException e){
        }catch(Exception e){
           System.exit(0);//Program terminates before executing finally block
        }finally{
            System.out.println("Won't be executed");
            System.out.println("No error");
        }
    }
}
+16
13 июл. '13 в 23:02
источник

Блок finally всегда выполняется, если нет аномального завершения программы, вызванного сбоем JVM или вызовом System.exit(0).

Кроме того, любое значение, возвращаемое из блока finally, переопределит значение, возвращаемое до выполнения блока finally, поэтому будьте осторожны при проверке всех точек выхода при окончательном использовании try.

+16
15 сент. '08 в 18:11
источник

Наконец, всегда выполняется, что вся точка, только потому, что она появляется в коде после возврата, не означает, что это было реализовано. Среда выполнения Java несет ответственность за запуск этого кода при выходе из блока try.

Например, если у вас есть следующее:

int foo() { 
    try {
        return 42;
    }
    finally {
        System.out.println("done");
    }
}

Среда выполнения создаст что-то вроде этого:

int foo() {
    int ret = 42;
    System.out.println("done");
    return 42;
}

Если вызывается неперехваченное исключение, будет выполняться блок finally, и исключение будет продолжать распространяться.

+10
13 мая '10 в 6:18
источник

Это связано с тем, что вы назначили значение я как 12, но не возвращали значение я в функцию. Правильный код выглядит следующим образом:

public static int test() {
    int i = 0;
    try {
        return i;
    } finally {
        i = 12;
        System.out.println("finally trumps return.");
        return i;
    }
}
+9
25 мая '10 в 6:36
источник

Да, он будет вызван. Это весь смысл наличия ключевого слова finally. Если выпрыгнуть из блока try/catch можно просто пропустить блок finally, это было бы то же самое, что и поставить System.out.println вне try/catch.

+8
15 сент. '08 в 17:46
источник

Вкратце, в официальной документации Java (нажмите здесь), написано, что -

Если JVM завершает работу, пока выполняется код try или catch, тогда блок finally может не выполняться. Аналогично, если выполнение потока код try или catch прерывается или убивается, блок finally может не выполняются, даже если приложение в целом продолжается.

+8
13 окт. '14 в 21:51
источник

Поскольку блок finally всегда будет вызываться, если вы не вызываете System.exit() (или поток не работает).

+8
13 мая '10 в 6:19
источник

Ответ прост ДА.

INPUT:

try{
    int divideByZeroException = 5 / 0;
} catch (Exception e){
    System.out.println("catch");
    return;    // also tried with break; in switch-case, got same output
} finally {
    System.out.println("finally");
}

ВЫВОД:

catch
finally
+8
13 авг. '16 в 7:00
источник

Да, будет. Только в случае, если это не произойдет, JVM выйдет или сработает

+7
14 янв. '14 в 22:29
источник

Да, блок finally всегда выполняется. Большинство разработчиков используют этот блок для закрытия соединения с базой данных, объекта результатов, объекта-оператора и также использования в спящем режиме java для отката транзакции.

+7
02 дек. '14 в 12:30
источник

Да, будет. Независимо от того, что происходит в вашем блоке try или catch, если иное не вызвано вызовом System.exit() или JVM. если в блоке (-ах) есть какой-либо оператор возврата, он, наконец, будет выполнен до этого оператора return.

+7
16 авг. '13 в 12:00
источник

Рассмотрим следующую программу:

public class SomeTest {

    private static StringBuilder sb = new StringBuilder();

    public static void main(String args[]) {

        System.out.println(someString());
        System.out.println("---AGAIN---");
        System.out.println(someString());
    }

    private static String someString() {

        try {
            sb.append("-abc-");
            return sb.toString();

        } finally {
            sb.append("xyz");
        }
    }
}

Начиная с Java 1.8.162, приведенный выше блок кода дает следующий вывод:

-abc-
---AGAIN---
-abc-xyz-abc-

это означает, что использование finally для освобождения объектов является хорошей практикой, подобной следующему коду:

private static String someString() {

    StringBuilder sb = new StringBuilder();

    try {
        sb.append("abc");
        return sb.toString();

    } finally {
        sb = null;
    }
}
+6
30 апр. '18 в 8:36
источник

То, что на самом деле истинно на любом языке..., наконец, всегда будет выполняться перед оператором return, независимо от того, где это возвращение находится в теле метода. Если бы это было не так, блок finally не имел бы большого значения.

+6
15 сент. '08 в 18:03
источник

В дополнение к вопросу о возврате в окончательной замене возврата в блоке try то же самое относится к исключению. Блок finally, который генерирует исключение, заменит возврат или исключение, вызванное из блока try.

+5
01 окт. '08 в 15:15
источник

Рассмотрим это в обычном ходе выполнения (т.е. без какого-либо исключения): если метод не является "void", он всегда явно возвращает что-то, но, наконец, всегда выполняется

+4
13 мая '10 в 11:50
источник

try - catch - finally являются ключевыми словами для использования случая обработки исключений.
Как нормальное объяснение

try {
     //code statements
     //exception thrown here
     //lines not reached if exception thrown
} catch (Exception e) {
    //lines reached only when exception is thrown
} finally {
    // always executed when the try block is exited
    //independent of an exception thrown or not
}

Блок finally предотвращает выполнение...

  • Когда вы вызывали System.exit(0);
  • Если JVM завершает работу.
  • Ошибки в JVM
+4
16 апр. '18 в 6:01
источник

Добавляем к @vibhash answer, поскольку никакой другой ответ не объясняет, что происходит в случае изменяемого объекта, такого как ниже.

public static void main(String[] args) {
    System.out.println(test().toString());
}

public static StringBuffer test() {
    StringBuffer s = new StringBuffer();
    try {
        s.append("sb");
        return s;
    } finally {
        s.append("updated ");
    }
}

Выведет

sbupdated 
+4
10 апр. '18 в 11:33
источник

Логический способ подумать об этом:

Код, помещенный в блок finally, должен быть выполнен независимо от того, что происходит в блоке try.

Итак, если код в блоке try пытается вернуть значение или выбросить исключение, элемент будет помещен 'на полку, пока блок finally не сможет выполнить Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или бросать все, что ему нравится. В этом случае все, что осталось на полке, отбрасывается.

Единственным исключением является то, что VM полностью отключается во время блока try, например. по 'System.exit

Никогда не бросайте исключение из блока finally

try {
  someMethod();  //Throws exceptionOne
} finally {
  cleanUp();    //If finally also threw any exception the exceptionOne will be lost forever
}

Это прекрасно, если cleanUp() никогда не может вызвать каких-либо исключений. В приведенном выше примере, если someMethod() выдает исключение, а в блоке finally также очищает исключение, то второе исключение выйдет из метода, и исходное первое исключение (правильная причина) будет потеряно навсегда. Если код, который вы вызываете в блоке finally, может вызвать исключение, убедитесь, что вы либо обрабатываете его, либо регистрируете его. Никогда не позволяйте этому выходить из блока finally.

Фактически выход из программы (либо путем вызова System.exit(), либо путем возникновения фатальной ошибки, из-за которой процесс прерывается: иногда его называют неофициально "горячей точкой" или "доктором Уотсоном" в Windows) блок от выполнения!

Нет ничего, что могло бы помешать нам вложить блоки try/catch/finally (например, поставить блок try/finally внутри блока try/catch или наоборот), и это не такая необычная вещь.

+4
22 дек. '15 в 5:12
источник

finally будет выполняться, и это точно.

finally не будет выполняться в следующих случаях:

случай 1:

Когда вы выполняете System.exit().

случай 2:

При сбое вашего JVM/Thread.

случай 3:

Когда ваше выполнение остановлено между вручную.

+4
18 дек. '14 в 6:36
источник
  • 1
  • 2

Посмотрите другие вопросы по меткам или Задайте вопрос