Подтвердить что ты не робот

Пояснение пробок-окончательного возврата

Прочитав все вопросы, заданные на этом форуме, связанные с темой выше (см. заголовок), я полностью понимаю, что finally всегда называется. (кроме System.exit и бесконечных циклов). Однако я хотел бы знать, вызывается ли return в блоке catch, а затем из блока finally вызывается другой return.

Например:

public static void main(String[]args) {
    int a = new TestClass().absorbeTheValue();
}

int absorbeTheValue() {
    try {
        int a = 10/0;
        if (a > 0) return 4;
    } catch(Exception e) {
        return 45;
    } finally {
        return 34;
    }
}    

Таким образом, вывод (когда будет вызван метод) будет в любом случае 34. Это означает, что, наконец, всегда запускается. Я думаю, что другие "возвращения" вообще не запускаются. Во многих сообщениях я обнаружил, что, наконец, напишу содержимое по тому, что уже было написано в результате возврата catch. Я понимаю, что как только возвращаемое значение в предложении catch должно быть оценено, поток управления переходит к предложению finally, которое, в свою очередь, возвращает другое, на этот раз результат будет оцениваться без передачи управления обратно в предложение catch, Таким образом, только return, вызываемый во время выполнения, будет окончательным возвратом. Вы согласны с этим?

A return в finally не возвращает элемент управления программе, но возвращает значение и завершает метод. Можем ли мы так сказать?

4b9b3361

Ответ 1

Если достигнут return в блоке try, он передает управление блоку finally, и функция в конечном итоге возвращается нормально (а не бросок).

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

В вашем примере у вас есть return в finally, поэтому независимо от того, что произойдет, функция вернет 34, потому что finally имеет окончательное (если хотите) слово.

Хотя это не относится к вашему примеру, это было бы правдой, даже если у вас не было catch, и если исключение было выбрано в блоке try и не было обнаружено. Выполняя return из блока finally, вы полностью исключаете исключение. Рассмотрим:

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

  private static int foo(String[] args) {
    try {
      int n = Integer.parseInt(args[0]);
      return n;
    }
    finally {
      return 42;
    }
  }
}

Если вы запустите это без предоставления каких-либо аргументов:

$ java FinallyReturn

... код в foo выдает ArrayIndexOutOfBoundsException. Но поскольку блок finally выполняет return, это исключение блокируется.

Это одна из причин, почему лучше избегать использования return в finally.

Ответ 2

Вот какой код, который показывает, как он работает.

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

    public static String test()
    {
        try {
            System.out.println("try");
            throw new Exception();
        } catch(Exception e) {
            System.out.println("catch");
            return "return"; 
        } finally {  
            System.out.println("finally");
            return "return in finally"; 
        }
    }
}

Результаты:

try
catch
finally
return in finally