Возвращаемое значение Java в режиме try-catch-finally
Я только что столкнулся с этим следующим кодом:
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".
Однако мне любопытно, что:
- Механизм внутренних функций в JVM. Кто-нибудь знает, действительно ли виртуальная машина заменяет возвращаемое значение в стеке, переписывая первый "возврат 1"? Если да, где я могу найти дополнительную информацию об этом.
- Мне еще предстоит найти использование для возврата в механизм finally, который используется таким образом и разрешен в реализованном
в JVM. Если эта конструкция кода используется как средство возврата
код ошибки, это, на мой взгляд, есть лучшие способы регистрации ошибок
или вернуть эти коды ошибок. Кто-нибудь нашел применение для такого
построить?
Большое спасибо заранее.
Cheers,
Верн
Ответы
Ответ 1
То, что я нашел в спецификации языка Java, по крайней мере определяет, что ваш фрагмент кода должен возвращать 3. Конечно, в нем не упоминается, как JVM должна реализовать это, и какие возможные оптимизации можно сделать.
Раздел 14.20.2 определяет, что
Если выполнение блока try завершается внезапно по какой-либо другой причине R, выполняется блок finally. Тогда есть выбор:
- Если блок finally завершается нормально, то оператор try завершается преждевременно по причине R.
- Если блок finally завершается преждевременно по причине S, то оператор try завершается преждевременно по причине S (и причина R отбрасывается).
И начало главы 14 (точнее,раздела 14.1) указывает, что такое нормальное и резкое завершение. Например, return
с заданным значением является неожиданным завершением.
Следовательно, в этом случае блок finally
завершается преждевременно (причина: return
с заданным значением), поэтому try
завершается внезапно по той же причине (и возвращает 3). Это подтверждается также в разделе 14.17 о выражении возврата as well
Если вычисление Выражения завершается нормально, производя значение V, тогда оператор return завершается преждевременно, причиной является возврат со значением V.
Ответ 2
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 реализует его, но самый простой способ взглянуть на него (по крайней мере концептуально):
- возвращаемое значение в "try" помещается в стек,
- тогда выполняется блок "finally",
- новое возвращаемое значение помещается в стек
- функция завершается, и возвращаемое значение выносится из стека, игнорируя первый.
Очень аккуратный вопрос.
Ответ 3
Реализация зависит от JVM, и существует много JVM. Вы можете вставить исходный код OpenJDK, чтобы увидеть, как он реализует finally
, но это не единственный способ сделать это. Что касается языка, важным является поведение.
Я не понимаю пункт 2 - почему существует finally
? это не так, как вы предлагаете как-то просто средство для возврата кода ошибки. Вам не нужно возвращаться из finally
вообще. Конструкция существует для обеспечения того, чтобы какой-то код очистки запускался после некоторого раздела кода независимо от того, как он завершается, как обычно, так и с помощью исключения или возврата.
Ответ 4
Полностью объяснено Страница: 439 = > http://docs.oracle.com/javase/specs/jls/se8/jls8.pdf
Если оценка Expression завершается нормально,
значение V, то оператор возврата завершается внезапно, причина, являющаяся возвратом
со значением V.
В предыдущих описаниях говорится "попытки передать управление", а не просто "передачи
control ", потому что если в методе или конструкторе есть какие-либо попытки (§14.20)
чьи блоки try или catch содержат оператор return, тогда любой
положения этих заявлений о попытках будут выполнены, чтобы быть наиболее внутренним до внешнего
управление передается вызову метода или конструктора. Резкое завершение
finally может нарушить передачу управления, инициированного оператором return.