Вопрос

Учитывая этот код, могу ли я быть абсолютно уверен что 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");
}
Это было полезно?

Решение

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

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

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

Другие советы

Пример кода:

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

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

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

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

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

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

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

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

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

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

ReturnStatement:
     return Expression(opt) ;

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

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

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

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

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

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 Block возвращает 2, а не 12, поскольку этот оператор возврата больше не выполняется.

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

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

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

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

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

  1. Код, помещенный в блокfinally, должен быть выполнен. что бы ни случилось внутри блока try
  2. Таким образом, если код в блоке try пытается вернуть значение или выдать исключение, элемент помещается «на полку», пока блокfinally не сможет выполниться.
  3. Поскольку код в блоке Final имеет (по определению) высокий приоритет, он может возвращать или выдавать все, что пожелает.В этом случае все, что осталось «на полке», выбрасывается.
  4. Единственное исключение из этого правила — если виртуальная машина полностью отключается во время блока try, например.от «System.exit»

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

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

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

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

Нет, не всегда один случай исключения // System.Exit (0);до того, как блок «finally» предотвратит выполнение «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");
        }
    }
}

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

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

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

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

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

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

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

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

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

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

ВХОД:

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

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

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

Если JVM выходит при выполнении кода Try или Catch, то Block, наконец, не выполняется.Аналогичным образом, если поток, выполняющий код Try или Catch, прерывается или убит, наконец -то блок может не выполняться, даже если приложение в целом продолжается.

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

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

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

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

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());
        System.out.println("---PRINT THE RESULT---");
        System.out.println(sb.toString());
    }

    private static String someString() {

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

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

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

-abc-
---AGAIN---
-abc-xyz-abc-
---PRINT THE RESULT---
-abc-xyz-abc-xyz

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

private static String someString() {

    StringBuilder sb = new StringBuilder();

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

    } finally {
        sb = null; // Just an example, but you can close streams or DB connections this way.
    }
}

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

finally выполнится и это точно.

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

Дело 1 :

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

случай 2:

Когда ваша JVM/Thread выходит из строя.

случай 3:

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

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

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

  2. Завершение программы из-за повреждения памяти.

  3. Вызвав System.exit()

  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
    }
}

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

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

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 

Я попробовал это, это одиночная резьба.

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, приведенный выше пример является одним из упоминаний третьего случая. здесь:

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

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

выход:Это не печатает «наконец», что означает, что «наконец-блок» в «потоке демона» не был выполнен.

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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top