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

2161

Учитывая этот код, могу ли я быть абсолютно уверен, что блок 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.");
}
  • 251
    Даже после самостоятельного тестирования вы знаете только то, что будет делать ваша реализация или версия Java / JVM, и не будете знать, что должен делать код (в соответствии со стандартом), и поэтому вопрос остается верным. Я рад видеть эти аспекты среди различных ответов.
  • 24
    Не всегда
Показать ещё 5 комментариев
Теги:
return
try-catch-finally

50 ответов

2411
Лучший ответ

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

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

  1. Если вы вызываете System.exit();
  2. Если сначала произойдет сбой JVM;
  3. Если JVM достигает бесконечного цикла (или другого не прерывающегося, не заканчивающегося оператора) в блоке try или catch;
  4. Если ОС принудительно завершает процесс JVM; например, "убить -9" в UNIX.
  5. Если хост-система умирает; например, сбой питания, аппаратная ошибка, паника ОС и т.д.
  6. Если, наконец, блок будет выполняться потоком демона, а все остальные не-демонные потоки выходят до того, как, наконец, вызывается.
  • 31
    На самом деле thread.stop() не обязательно препятствует выполнению блока finally .
  • 146
    Как насчет того, чтобы сказать, что блок finally будет вызываться после блока try и перед передачей управления следующим операторам. Это согласуется с блоком try, включающим бесконечный цикл и, следовательно, блок finally, который фактически никогда не вызывается.
Показать ещё 26 комментариев
460

Пример кода:

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
  • 14
    К вашему сведению: в C # поведение идентично, за исключением того факта, что замена оператора в предложении finally с return 2; не допускается (ошибка компилятора).
  • 13
    Вот важная деталь, о которой следует знать: stackoverflow.com/a/20363941/2684342
Показать ещё 5 комментариев
345

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

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

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

  • 85
    Это действительно плохая практика. См. Stackoverflow.com/questions/48088/… для получения дополнительной информации о том, почему это плохо.
  • 19
    Согласовано. Возврат в finally {} игнорирует любое исключение, выданное в try {}. Страшно!
Показать ещё 6 комментариев
241

Вот официальные слова из спецификации языка 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.

144

В дополнение к другим ответам важно указать, что "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();
    }
}
  • 59
    Следует отметить, что средний регистр является именно той причиной, по которой наличие оператора return внутри блока finally абсолютно ужасно (он может скрыть любой Throwable).
  • 0
    Кто не хочет, чтобы OutOfMemoryError ? ;)
99

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

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.

  • 4
    Этот пример потрясающий, он добавляет то, что не было упомянуто в десятках, наконец, связанных тем. Я думаю, что едва ли любой разработчик будет знать это.
  • 4
    Что если бы i был не примитивом, а объектом Integer.
Показать ещё 5 комментариев
96

Вот разработка ответа Кевина. Важно знать, что возвращаемое выражение оценивается до 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
  • 4
    Важно знать.
47

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

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

37

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

  • Код, помещенный в блок finally, должен быть выполнен независимо от того, что происходит в блоке try
  • Итак, если код в блоке try пытается вернуть значение или выбросить исключение, элемент будет помещен "на полку" до тех пор, пока блок finally не сможет выполнить
  • Поскольку код в блоке finally имеет (по определению) высокий приоритет, он может возвращать или бросать все, что ему нравится. В этом случае все, что осталось на полке, отбрасывается.
  • Единственным исключением из этого является то, что VM полностью отключается во время блока try, например. по 'System.exit'
  • 10
    Это просто «логичный способ думать об этом» или действительно, как блок finally должен работать в соответствии со спецификациями? Ссылка на ресурс Sun была бы очень интересна здесь.
18

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

17

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

16

Нет, не всегда один случай исключения //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");
        }
    }
}
  • 0
    И это одна из причин, по которой вам никогда не следует вызывать System.exit () ...
16

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

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

10

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

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

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

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

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

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

9

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

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

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

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
  • 1
    Ответ прост НЕТ.
  • 1
    @ChristopheRoussy Как? Объясните пожалуйста?
Показать ещё 3 комментария
8

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

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

8

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

8

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

7

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

7

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

7

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

6

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

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;
    }
}
  • 0
    sb.setLength(0) это не должно быть sb.setLength(0) в наконец?
  • 0
    sb.setLength (0) просто очистит данные в StringBuffer. Таким образом, sb = null отсоединит объект от ссылки.
Показать ещё 5 комментариев
6

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

  • 0
    Не каждый язык, finally на первом месте ...
5

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

4

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

Добавляем к @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 
  • 0
    Начиная с Java 1.8.162, это не вывод.
4

Да, потому что без оператора управления может предотвратить выполнение finally.

Вот пример ссылки, где будут выполняться все блоки кода:

| x | Current result | Code 
|---|----------------|------ - - -
|   |                |     
|   |                | public static int finallyTest() {
| 3 |                |     int x = 3;
|   |                |     try {
|   |                |        try {
| 4 |                |             x++;
| 4 | return 4       |             return x;
|   |                |         } finally {
| 3 |                |             x--;
| 3 | throw          |             throw new RuntimeException("Ahh!");
|   |                |         }
|   |                |     } catch (RuntimeException e) {
| 4 | return 4       |         return ++x;
|   |                |     } finally {
| 3 |                |         x--;
|   |                |     }
|   |                | }
|   |                |
|---|----------------|------ - - -
|   | Result: 4      |

В следующем варианте return x; будет пропущен. Результат по-прежнему 4:

public static int finallyTest() {
    int x = 3;
    try {
        try {
            x++;
            if (true) throw new RuntimeException("Ahh!");
            return x; // skipped
        } finally {
            x--;
        }
    } catch (RuntimeException e) {
        return ++x;
    } finally {
        x--;
    }
}

Ссылки, конечно, отслеживают их статус. В этом примере возвращается ссылка с помощью value = 4:

static class IntRef { public int value; }
public static IntRef finallyTest() {
    IntRef x = new IntRef();
    x.value = 3;
    try {
        return x;
    } finally {
        x.value++; // will be tracked even after return
    }
}
4

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

Код, помещенный в блок 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

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

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

случай 1:

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

случай 2:

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

случай 3:

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

  • 0
    Случай 3 неверен, см. Stackoverflow.com/a/27117795/2340939 .
  • 0
    user2340939: ответ исправлен
4

Наконец, блок всегда выполняет ли дескриптор исключений или нет. Если какое-либо исключение произошло до того, как попытаться выполнить блок, то окончательный блок не будет выполняться.

4

Если генерируется исключение, оно, наконец, запускается. Если исключение не выбрасывается, оно, наконец, запускается. Если исключение поймано, он, наконец, запускается. Если исключение не поймано, он, наконец, запускается.

Только время, когда он не запускается, - это когда JVM завершает работу.

4

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

4

Потому что окончательный всегда вызывается в любых случаях, которые у вас есть. У вас нет исключения, оно все еще называется catch catch, оно все еще называется

3

Да, написано здесь

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

3

Блок finally не будет вызываться после возврата в нескольких уникальных сценариях: если сначала вызывается System.exit(), или если JVM аварийно завершает работу.

Позвольте мне попытаться ответить на ваш вопрос самым простым способом.

Правило 1: блок finally всегда запускается  (Хотя есть исключения из этого, но пусть будет придерживаться этого на некоторое время.)

Правило 2: инструкции в блоке finally запускаются, когда элемент управления оставляет попытку или блок catch. Передача элемента управления может произойти в результате нормального выполнения, выполнения прерывания, продолжения, goto или оператор return, или пропозиция исключения.

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

В случае, если в блоке finally также есть оператор return, он определенно переопределит тот, который ожидает от блока try, поскольку он очищает стек вызовов.

Здесь вы можете найти лучшее объяснение: http://msdn.microsoft.com/en-us/.... концепция в основном одинакова на всех языках высокого уровня.

3

Если вы не обрабатываете исключение, перед завершением программы JVM выполняет окончательный блок. Он не будет выполняться только в том случае, если нормальное выполнение программы не будет означать прекращение программы из-за следующих причин.

  • Вызывая фатальную ошибку, которая приводит к прерыванию процесса.

  • Прекращение программы из-за повреждения памяти.

  • Вызовите System.exit()

  • Если программа переходит в бесконечный цикл.

3
  • Наконец, блок всегда выполняется. Пока и до Существует System.exit() (первый оператор в блоке finally).
  • Если system.exit() - это первый оператор, то, наконец, блок не будет выполнен, а управление будет выведено из блока finally. Всякий раз, когда оператор System.exit() получает окончательный блок до тех пор, пока этот оператор окончательно не будет выполнен, а когда появится System.exit(), тогда из блока finally полностью выйдет управляющее усилие.
  • 1
    На этот вопрос много раз отвечали, так какую новую информацию добавляет ваш ответ?
3

Я попробовал это, это однопоточный.

class Test {
    public static void main(String args[]) throws Exception {
       Object obj = new Object();
       try {
            synchronized (obj) {
            obj.wait();
            System.out.println("after wait()");
           }
       } catch (Exception e) {
       } finally {
           System.out.println("finally");
       }
   }
}

Основной поток будет находиться в состоянии ожидания навсегда, поэтому, наконец, никогда не будет вызван,

поэтому консольный вывод не будет печатать строку: after wait() или finally

Согласившись с @Stephen C, приведенный выше пример является одним из упоминаний о 3-м случае здесь: https://stackoverflow.com/questions/65035/does-a-finally-block-always-get-executed-in-java

Добавим еще несколько таких возможностей бесконечного цикла в следующем коде:

// import java.util.concurrent.Semaphore;
class Test {
    public static void main(String[] args) {
        try {
            // Thread.sleep(Long.MAX_VALUE);
            // Thread.currentThread().join();
            // new Semaphore(0).acquire();
            // while (true){}
            System.out.println("after sleep join semaphore exit infinite while loop");
        } catch (Exception e) {
        } finally {
            System.out.println("finally");
        }
    }
}

Случай 2: если JVM аварийно завершает работу

import sun.misc.Unsafe;
import java.lang.reflect.Field;
class Test {
    public static void main(String args[]) {
        try {
            unsafeMethod();
//            Runtime.getRuntime().halt(123);
            System.out.println("After Jvm Crash!");
        } catch (Exception e) {
        } finally {
            System.out.println("finally");
        }
    }

    private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
        Field f = Unsafe.class.getDeclaredField("theUnsafe");
        f.setAccessible(true);
        Unsafe unsafe = (Unsafe) f.get(null);
        unsafe.putAddress(0, 0);
    }
}

Ссылка: как вы разбили JVM?

Случай 6: если блок finally будет выполняться потоком демона, и все остальные потоки, не являющиеся демонами, завершат работу до вызова finally.

class Test {
    public static void main(String args[]) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    printThreads("Daemon Thread printing");
                    // just to ensure this thread will live longer than main thread
                    Thread.sleep(10000);
                } catch (Exception e) {
                } finally {
                    System.out.println("finally");
                }
            }
        };
        Thread daemonThread = new Thread(runnable);
        daemonThread.setDaemon(Boolean.TRUE);
        daemonThread.setName("My Daemon Thread");
        daemonThread.start();
        printThreads("main Thread Printing");
    }

    private static synchronized void printThreads(String str) {
        System.out.println(str);
        int threadCount = 0;
        Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
        for (Thread t : threadSet) {
            if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
                System.out.println("Thread :" + t + ":" + "state:" + t.getState());
                ++threadCount;
            }
        }
        System.out.println("Thread count started by Main thread:" + threadCount);
        System.out.println("-------------------------------------------------");
    }
}

вывод: Это не выводит "finally", что означает, что "блок finally" в "потоке демона" не был выполнен

main Thread Printing  
Thread :Thread[My Daemon Thread,5,main]:state:BLOCKED  
Thread :Thread[main,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE   
Thread count started by Main thread:3  
-------------------------------------------------  
Daemon Thread printing  
Thread :Thread[My Daemon Thread,5,main]:state:RUNNABLE  
Thread :Thread[Monitor Ctrl-Break,5,main]:state:RUNNABLE  
Thread count started by Main thread:2  
-------------------------------------------------  

Process finished with exit code 0
  • 3
    Смотрите принятый ответ. Это просто крайний случай «бесконечного цикла».
3

НЕ ВСЕГДА

Спецификация языка Java описывает, как блоки try-catch-finally и try-catch работают в 14.20.2
Ни в каком месте это не указывает, что блок finally всегда выполняется. Но для всех случаев, в которых завершаются блоки try-catch-finally и try-finally, указывается, что перед выполнением должны быть выполнены, наконец, finally.

try {
  CODE inside the try block
}
finally {
  FIN code inside finally block
}
NEXT code executed after the try-finally block (may be in a different method).

JLS не гарантирует, что FIN выполняется после CODE. JLS гарантирует, что если выполняются CODE и NEXT, то FIN всегда будет выполняться после CODE и до NEXT.

Почему JLS не гарантирует, что блок finally всегда выполняется после блока try? Потому что это невозможно. Маловероятно, но возможно, что JVM будет прервана (kill, crash, power off) сразу после завершения блока try, но перед выполнением блока finally. JLS ничего не может сделать, чтобы избежать этого.

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

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

3

Попробуйте этот код, вы поймете, что код в блоке finally выполняется после оператора return.

public class TestTryCatchFinally {
    static int x = 0;

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

    public static int f1(){
        try{
            x = 1;
            return x;
        }finally{
            x = 2;
        }
    }

    public static int f2(){
        return x;
    }
}
2

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

try{
//risky code
}catch(Exception e){
//exception handling code
}
finally(){
//It always execute but before this block if there is any statement like System.exit(0); then this block not execute.
}
  • 0
    Дубликативный ответ
2

То же самое со следующим кодом:

static int f() {
    while (true) {
        try {
            return 1;
        } finally {
            break;
        }
    }
    return 2;
}

f вернет 2!

  • 0
    Дубликативный ответ
2

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

try{
}finally{
   try{
   }finally{
      //if(someCondition) --> no error because of unreachable code
      throw new RunTimeException();
   }
   int a = 5;//unreachable code
}
  • 1
    Просто отмечаю, что это совершенно нормальное поведение. Любой / весь код завершается преждевременно, если выдается исключение. Это ничем не отличается от исключения, созданного где-либо еще. В спецификации нет специального правила, которое гласит: «Исключения нельзя использовать внутри блока finally». Из-за этого я даже сначала неправильно понял ваш ответ и почти дал -1, пока не перечитал его пару раз.
  • 0
    Хорошо, но как возврат отличается от броска? Если вы вернетесь, то блок должен вернуться, но в блоке finally возвращение будет отложено, и для него есть какое-то странное исключение, поэтому не ясно, что finally обрабатывает throw обычным способом. Это главная причина, почему я написал это тогда. Кроме того, добавление блока try или catch не помешает выполнению блока finally, поэтому, конечно. Можно ожидать, что когда вы добавляете блок finally, он все еще выполняется.
Показать ещё 2 комментария
2

Я был очень смущен всеми ответами, представленными на разных форумах, и решил окончательно закодировать и посмотреть. Вывод:

, наконец, будет выполнен, даже если в блоке try и catch есть возврат.

try {  
  System.out.println("try"); 
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} catch (Exception e) {   
  System.out.println("catch");
  return;
  //int  i =5/0;
  //System.exit(0 ) ;
} finally {  
   System.out.println("Print me FINALLY");
}

Выход

попробовать

Напечатайте меня НАКОНЕЦ

  1. Если return заменяется на System.exit(0) в try и catch block в приведенном выше коде, и по какой-либо причине перед ним возникает исключение.
1

Наконец, он всегда называется в конце

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

Наконец, обычно используется при очистке, например, если вы используете сканер в java, вероятно, вы должны закрыть сканер, поскольку это приводит к другим проблемам, таким как невозможность открыть какой-либо файл

1
Блок

finally выполняется всегда, даже если вы поместите оператор return в блок try. Блок finally будет выполнен перед оператором return.

-2

Я хотел бы поделиться вами, код в блоке finally будет почти всегда выполняться.

  • Если исключение вызывает выполнение блока catch, блок finally будет выполняться после блока catch.
  • Если возникает неперехваченное исключение, выполняется блок finally и то выполнение завершает этот метод, и исключение метод, который вызвал этот метод.
  • Если либо блок try, либо блок catch выполняет возврат , блок finally выполняется до того, как мы покинем этот метод.
  • Если либо блок try, либо блок catch вызывает System.exit, блок finally не будет выполнен.
  • Для полноты, если блок finally выполняет возврат в то время как неперехваченное исключение находится в ожидании, исключение заглушается; то есть он просто исчезает.

    попробовать {
    рискованный блок кода

    } catch (ExceptionClassName exceptionObjectName) {
    код для решения проблемы

    } наконец {
    код, который всегда будет выполнять

    }

-3

окончательно блокировать выполнение всегда, независимо от объекта исключения, или нет.

есть две возможности остановить блок finally: 1. выражение о возврате. 2. System.exit(0);

public class test{
  public static void main(String[] args){
   if(true) {
   return;
   }

   try{
    System.out.println(1);
    return;
-5

Да, в блоке try/catch/finally окончательно будет вызываться. Однако в вашем примере:

try {
   something();
   return success; // Will return out of the method if successful.
} catch (Exception ex) {
   return failure; // Will return out of the method if not successful.
} finally {
   // Possibly unreachable code.
   System.out.println("I'm not sure if this will be printed...");
}

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

public boolean runSomething () {
    boolean isSuccess = true;
    try {
       something(); // Runs thread. If successful, run finally block.
    } catch (Exception ex) {
       // If exception is caught, display (if desired) exception and set
       // the out bound variable to false. Finally, run finally block.
       System.out.println("Exception: " + ex.toString());
       isSuccess = false;
    } finally {
       System.out.println("This was executed in the finally.");
    }
    return isSuccess; // Returns success flag.
}

Я понимаю, что этой должности 5 лет, но я надеюсь, что это поможет кому-то! Ура!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню