Попробуй-поймай-наконец-верни разъяснение

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

Например:

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 return. Насколько я понимаю, как только возвращаемое значение в предложении catch будет оцениваться, поток управления переходит к предложению finally, которое, в свою очередь, имеет еще один возврат, на этот раз возврат будет оцениваться без передачи управления обратно в предложение catch . Таким образом, единственный return, вызываемый во время выполнения, будет окончательным возвратом. Согласны ли вы с этим?

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


person Rollerball    schedule 05.03.2013    source источник
comment
Сделайте отступ, пожалуйста.   -  person Giovani Guizzo    schedule 05.03.2013
comment
См. Также: stackoverflow.com/questions/65035 /   -  person Has QUIT--Anony-Mousse    schedule 05.03.2013
comment
какой у Вас вопрос??   -  person thiagoh    schedule 05.03.2013


Ответы (2)


Если достигается 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.

person T.J. Crowder    schedule 05.03.2013
comment
Важно отметить, что для этих целей throw будет взаимозаменяем с return. (например, throw new Exception(4), throw new exception(34)) - person Marcus; 17.08.2013
comment
Я просто хочу поделиться тем, что сказал пользователь 1442960. JLS ничего не говорит о возврате в улове или в конце. Он использует этот термин резко, что, как я предполагаю, означает либо исключение, либо возврат. - person Steve11235; 19.11.2013
comment
@ Steve11235: Нет, return из блока catch будет выполняться нормально, а не резко. Это достаточно ясно из Раздел 11: Во время создания исключения виртуальная машина Java внезапно завершает, одно за другим, любые выражения, операторы, вызовы методов и конструкторов, инициализаторы и выражения инициализации полей, которые начали, но не завершили выполнение в текущем потоке. - person T.J. Crowder; 10.08.2014

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

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
person andre    schedule 05.03.2013
comment
+1 легко понять и научил меня чему-то новому :) - person ldam; 05.03.2013
comment
@LoganDam Т.Дж. Краудер дает очень хорошее объяснение. - person andre; 05.03.2013
comment
@LoganDam: это хорошее четкое объяснение порядка операций. Однако это не отвечает на заданный вопрос. Вопрос явно спрашивает о том, что происходит, когда блок finally содержит оператор return. - person unholysampler; 05.03.2013
comment
@unholysampler хороший улов, я обновил ответ. Спасибо. - person andre; 05.03.2013
comment
И я снова узнал кое-что новое... так держать, ребята! - person ldam; 05.03.2013
comment
хороший случай, чтобы проверить, как работает поток управления. Очень интересно - person ShanJay; 23.11.2013
comment
с return он возвращается к следующему оператору после «try-catch-finally»? или он выходит из функции? Вы должны добавить это к своему примеру. - person Nulik; 06.01.2017