У меня есть простой класс Java, как показано ниже:
public class Test {
private String s;
public String foo() {
try {
s = "dev";
return s;
}
finally {
s = "override variable s";
System.out.println("Entry in finally Block");
}
}
public static void main(String[] xyz) {
Test obj = new Test();
System.out.println(obj.foo());
}
}
И вывод этого кода такой:
Entry in finally Block
dev
Почему s
не переопределяется в finally
блоке, а контролируется вывод на печать?
java
try-finally
Dev
источник
источник
s
прежде чем изменить его значение.finally
блоке , в отличие от C # (что вы не можете)Ответы:
В
try
блоке завершается с исполнениемreturn
заявления и стоимостьюs
на моментreturn
оператор выполняет это значение , возвращаемое методом. Тот факт, чтоfinally
предложение позже изменяет значениеs
(после завершенияreturn
оператора), не изменяет (в этот момент) возвращаемое значение.Обратите внимание, что вышеизложенное касается изменений самого значения
s
вfinally
блоке, а не объекта, на которыйs
ссылается. Если быs
была ссылка на изменяемый объект (аString
это не так) и содержимое объекта было изменено вfinally
блоке, то эти изменения будут видны в возвращаемом значении.Подробные правила того, как все это работает, можно найти в разделе 14.20.2 спецификации языка Java. . Обратите внимание, что выполнение
return
оператора считается внезапным завершениемtry
блока (применяется раздел, начинающийся с « Если выполнение блока try завершается внезапно по любой другой причине R .... »). См. Раздел 14.17 JLS, чтобы узнать, почемуreturn
оператор является внезапным завершением блока.Более подробно: если как
try
блок, так иfinally
блокtry-finally
оператора внезапно завершаются из-заreturn
операторов, то применяются следующие правила из §14.20.2:В результате
return
оператор вfinally
блоке определяет возвращаемое значение всегоtry-finally
оператора, а возвращаемое значение изtry
блока отбрасывается. Подобное происходит вtry-catch-finally
операторе, еслиtry
блок выдает исключение, он перехватываетсяcatch
блоком, и уcatch
блока и уfinally
блока естьreturn
операторы.источник
finally
блок не меняет, какой объект возвращается (StringBuilder
), но он может изменить внутреннюю часть объекта. Вfinally
блоке выполняется перед методом фактически возвращает (даже еслиreturn
оператор закончил), так что эти изменения происходят до того , как код вызова видит возвращаемое значение.StringBuilder
,List
,Set
, объявление до тошноты): если вы меняете содержимое вfinally
блоке, то эти изменения проявляются в вызывающем коде , когда метод , наконец , завершает свою работу.Потому что возвращаемое значение помещается в стек перед вызовом finally.
источник
=
не изменило бы его.finally
блок OP не влияет на возвращаемое значение. Я думаю, что то, к чему может привести templatetypedef (хотя это не ясно), это то, что возвращаемое значение является ссылкой на неизменяемый объект, даже изменяя код вfinally
блоке (кроме использования другогоreturn
оператора) не может повлиять на значение, возвращаемое из метода.Если мы заглянем внутрь байт-кода, то заметим, что JDK провел значительную оптимизацию, а метод foo () выглядит следующим образом:
И байт-код:
java сохранил строку «dev» от изменения до возвращения. На самом деле здесь нет окончательного блока вообще.
источник
Здесь следует отметить 2 вещи:
источник
finally
предложении, это будет видно в вызывающем коде. Однако, если вы назначите новый буфер строкs
, то поведение будет таким же, как и сейчас.Я немного изменил твой код, чтобы доказать смысл Теда.
Как видите, выход
s
действительно изменился, но после возврата.Вывод:
источник
Технически говоря,
return
блок try не будет игнорироваться, еслиfinally
блок определен, только если этот блок finally также включает в себяreturn
.Это сомнительное дизайнерское решение, которое, вероятно, было ошибкой в ретроспективе (очень похоже на то, что ссылки по умолчанию могут быть обнуляемыми / изменяемыми и, по некоторым данным, проверенными исключениями). Во многих отношениях это поведение в точности соответствует разговорному пониманию того, что
finally
означает - «независимо от того, что происходит заранее вtry
блоке, всегда выполняйте этот код». Следовательно, если вы возвращаете true изfinally
блока, общий эффект всегда должен бытьreturn s
, нет?В общем, это редко хорошая идиома, и вы должны
finally
свободно использовать блоки для очистки / закрытия ресурсов, но редко, если когда-либо возвращаете значение из них.источник
Попробуйте это: если вы хотите напечатать значение переопределения s.
источник