Возвращаемое значение Java в механизме try-catch-finally - PullRequest
13 голосов
/ 14 января 2012

Я только что столкнулся с этим кодом:

public class TestFinally {
    public static void main(String[] args) {
        int returnValue = function();

        System.out.println("Return value: " + returnValue);
    }

    public static int function() {
        try {
            return 1;
        } catch (Exception e){
            return 2;
        } finally{
            return 3;
        }
    }
}

Без сомнения, выполнение этого кода приведет к выводу «Возвращаемое значение: 3».

Однако мне любопытно:

  1. Механизм внутренностей в JVM. Кто-нибудь знает, действительно ли виртуальная машина заменяет возвращаемое значение в стеке путем перезаписи первого «return 1»? Если так, где я могу найти больше информации об этом.
  2. Мне еще предстоит найти применение для возврата в механизме finally, который используется таким образом и разрешен в реализованном в JVM. Если эта конструкция кода используется как средство для возврата код ошибки, на мой взгляд, есть лучшие способы регистрации ошибок или верните эти коды ошибок. Кто-нибудь нашел применение для такого построить?

Большое спасибо заранее.

Cheers, Верн

Ответы [ 4 ]

13 голосов
/ 14 января 2012

То, что я нашел в спецификации языка Java, по крайней мере определяет, что ваш фрагмент кода должен возвращать 3. Конечно, в нем не упоминается, как JVM должна реализовать это, и какие возможные оптимизации можно сделать.

Раздел 14.20.2 определяет, что

Если выполнение блока try завершается внезапно по любой другой причине R, то выполняется блок finally.Тогда есть выбор:

  1. Если блок finally завершается нормально, то оператор try завершается преждевременно по причине R.
  2. Если блок finally завершается внезапно по причине S, тогдаОператор try завершается преждевременно по причине S (и причина R отбрасывается).

И начало главы 14 ( раздел 14.1 , если быть более точным) указывает, что является нормальными резкое завершение есть.Например, return с заданным значением является внезапным завершением.

Следовательно, в этом случае блок finally завершается внезапно (причина: return с заданным значением), поэтому tryзавершится внезапно по той же причине (и вернет 3).Это подтверждается в разделе 14.17 об операторе возврата , а также

Если вычисление выражения завершается нормально, производя значение V, то оператор возврата завершается внезапно, причина в том, чтовозврат со значением V.

5 голосов
/ 14 января 2012

FWIW, я получаю предупреждение о функции:

public static int function(){
    try{
        return 1;
    }catch(Exception e){
        return 2;
    }finally{
        return 3; //WARNING on this line
    }
}

Т.е.он говорит мне "наконец, блок не завершается нормально".Я все еще получаю 3 как возвращенное значение, несмотря ни на что.

В любом случае, если я попробую этот другой пример:

public class TestFinally {
    public static void main(String[] args) {
        int returnValue = function();

        System.out.println("Return value: " + returnValue);
    }

    public static int function() {
        try {  

            return 1;  
            }  
        catch (Exception e) {   
            return 2;  
            }  
        finally {  
            System.out.println("i don't know if this will get printed out.");
        }
    }
}

результат будет (очевидно)

i don't know if this will get printed out.
Return value: 1

Я понятия не имею, как его реализует JVM,но самый простой способ взглянуть на это (по крайней мере, концептуально) будет:

  1. возвращаемое значение в "try" помещается в стек,
  2. , затем "finally"выполняется блок,
  3. новое возвращаемое значение помещается в стек
  4. , выход из функции и возвращаемое значение выталкивается из стека, игнорируя первое.

Очень аккуратный вопрос.

4 голосов
/ 14 января 2012

Реализация зависит от JVM, и есть много JVM. Вы можете покопаться в исходном коде OpenJDK , чтобы увидеть, как он реализует finally, но это не единственный способ сделать это. Что касается языка, главное - это поведение.

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

0 голосов
/ 10 мая 2014

Полностью объясненная страница: 439 => http://docs.oracle.com/javase/specs/jls/se8/jls8.pdf

Если оценка Выражения завершается нормально, производя значение V, то оператор возврата завершается внезапно, причина возврата со значением V.

В предыдущих описаниях говорится "попытки передать контроль", а не просто "переводит" control ", потому что если есть какие-либо операторы try (§14.20) внутри метода или конструктора чьи блоки try или catch содержат оператор return, затем любой finally предложения этих операторов try будут выполняться по порядку, от самого внутреннего до самого внешнего, до управление передается вызывающему методу или конструктору. Резкое завершение Предложение finally может нарушить передачу управления, инициированную оператором return.

...