Вопрос: Выполняется ли окончательно на 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.");
}

1859


источник


Ответы:


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

Единственные времена finallyне будут называться:

  1. Если вы вызываете System.exit();
  2. Если сначала произойдет сбой JVM;
  3. Если JVM достигает бесконечного цикла (или некоторого другого не прерывающегося, не заканчивающегося оператора) в tryили catchблок;
  4. Если ОС принудительно завершает процесс JVM; например «kill -9» в UNIX.
  5. Если хост-система умирает; например сбой питания, аппаратная ошибка, паника ОС и т. д.

2054



Пример кода:

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

433



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

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

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


318



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

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

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

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

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

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

ReturnStatement:
     return Expression(opt) ;

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

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

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


227



В дополнение к другим ответам важно указать, что «наконец» имеет право переопределить любое исключение / возвращаемое значение блоком 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();
    }
}

131



Я попробовал приведенный выше пример с небольшими изменениями -

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выполняется.

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

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


84



Here's an elaboration of Kevin's answer. It's important to know that the expression to be returned is evaluated before finally, even if it is returned after.

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");
    }
}

Output:

X
finally trumps return... sort of
0

78



That is the whole idea of a finally block. It lets you make sure you do cleanups that might otherwise be skipped because you return, among other things, of course.

Finally gets called regardless of what happens in the try block (unless you call System.exit(int) or the Java Virtual Machine kicks out for some other reason).


45



A logical way to think about this is:

  1. Code placed in a finally block must be executed whatever occurs within the try block
  2. So if code in the try block tries to return a value or throw an exception the item is placed 'on the shelf' till the finally block can execute
  3. Because code in the finally block has (by definition) a high priority it can return or throw whatever it likes. In which case anything left 'on the shelf' is discarded.
  4. The only exception to this is if the VM shuts down completely during the try block e.g. by 'System.exit'

31



Also a return in finally will throw away any exception. http://jamesjava.blogspot.com/2006/03/dont-return-in-finally-clause.html


14



finally is always executed unless there is abnormal program termination (like calling System.exit(0)..). so, your sysout will get printed


12