Выполняется ли finally если в try return?

143
17 февраля 2019, 12:30
try {
  ...
  return qwe;
} catch {...}
finally {...}

Выполняется ли finally если в try есть return?

Answer 1

Конечно. На то он и finally. Правда результат может немного озадачить.

import java.util.*;
import java.lang.*;
class Main
{
        public static int test() {
          try {
            System.out.println("test");
            return 1;
          }
          finally {
            System.out.println("fin"); 
            return 2;
          }
          //return 3;
        }
        public static void main (String[] args) throws java.lang.Exception
        {
                int i = test();
                System.out.println("test return " + i);
        }
}

вывод будет такой:

test
fin
test return 2

а вот строку с return 3; не даст раскомментировать компилятор.

Answer 2

Finlally выполняется почти всегда.

Update, хотел бы дополнить мой ответ по поводу обработки исключений в java. Рассмотрим 3 случая, которые показались мне интересными. Вот метод testFinally()

static int testFinally() {
    for (int i = 0; i < 10; i++) {
      System.out.println("i = " + i);
      try {
        if (i == 3) {
          throw new Exception();
        }
      } catch (Exception e) {
        System.out.println("Exception!");
        return i;
      } finally {
        System.out.println("Finally ");
      }
    }
    return -1;
  }

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

Второй случае связан с многопточностью, вернее с тем фактом что, это правило также справедливо и для многопоточных приложений.

 public static void main(String[] args) throws Exception {
    Thread t = new Thread(new Runnable(){
    public void run() {
    try {
      for (int i = 0; i < 10; i++) {
        System.out.println(Thread.currentThread() + ": " + i);
        TimeUnit.SECONDS.sleep(1);
      }
    } catch (InterruptedException e) {
      System.out.println("Interrupted!");
    } finally {
      System.out.println("I'm in the finally block!");
    }
  }
  });
    t.start();
    TimeUnit.SECONDS.sleep(5);
    System.out.println("main() finished");
  }
}

Тут тоже все будет правильно, то есть блок finally отработает. Но не для потоков демонов. Как ни странно, джава прибьет их и не подавиться без выполнение блоков фанали.

 public static void main(String[] args) throws Exception {
    Thread t = new Thread(new Runnable(){
    public void run() {
    try {
      for (int i = 0; i < 10; i++) {
        System.out.println(Thread.currentThread() + ": " + i);
        TimeUnit.SECONDS.sleep(1);
      }
    } catch (InterruptedException e) {
      System.out.println("Interrupted!");
    } finally {
      System.out.println("I'm in the finally block!");
    }
  }
  });
    t.setDaemon(true);
    t.start();
    TimeUnit.SECONDS.sleep(5);
    System.out.println("main() finished");
  }
}

Что доказывает что везде есть исключения, даже в исключениях)

Answer 3

В дополнение к существующим ответам привожу ссылки на соответствующие разделы документации.

Почему finally должен вызываться после return описано в спецификации языка Java в главах по return и finally:

14.17. The return Statement
...
A return statement with an Expression attempts to transfer control to the invoker of the method or lambda body that contains it; the value of the Expression becomes the value of the method invocation. More precisely, execution of such a return statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the return statement completes abruptly for that reason. If evaluation of the Expression completes normally, producing a value V, then the return statement completes abruptly, the reason being a return with value V.

14.20.2. Execution of try-finally and try-catch-finally
...
If execution of the try block completes abruptly for any other reason R, then the finally block is executed, and then there is a choice:
- If the finally block completes normally, then the try statement completes abruptly for reason R.
- If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

Перевод:

14.17. Инструкция return
...
Инструкция return с выражением Expression пытается передать управление коду, вызвавшему метод или лямбда-выражение, содержащее эту инструкцию; значение Expression становится значением вызова метода. Говоря более строго, выполнение такой инструкции return сначала вычисляет Expression. Если вычисление Expression завершается преждевременно по некоторой причине, инструкция return завершается преждевременно по той же самой причине. Если вычисление Expression завершается нормально, давая значение V, то инструкция return завершается преждевременно по той причине, что она является возвратом значения V

14.20.2. Выполнение try-finally и try-catch-finally
...
Если выполнение блока try завершается преждевременно по некоторой иной причине R, выполняется блок finally. Далее возможны следующие варианты.
- Если блок finally завершается нормально, то инструкция try завершается преждевременно по причине R.
- Если блок finally завершается преждевеременно S, инструкция try завершается преждевременно по причине S (причина R игнорируется).

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

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

Answer 4

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

Взято здесь: https://programming.guide/java/try-finally.html

READ ALSO
Использование свойства потока IsAlive

Использование свойства потока IsAlive

Разбирая тему многопоточности по Шиелду 40, столкнулся с проблемой

163
Elasticsearch поиск по полю

Elasticsearch поиск по полю

Есть сервер Elsaticsearch с ним общаюсь по средствам Nest

172
Создание мультиязычного меню

Создание мультиязычного меню

создал мультиязычное меню, но при обращении к нему выводить такую ошибку Call to a member function getDataMenu() on arrayГде я ошибся? Вот код виджета

177
автообновление парсера php

автообновление парсера php

Есть парсер на php,

127