Давайте рассмотрим тестовый класс
import java.util.Date;
public class TestClass {
public String finallyHappensBeforeReturn(){
try{
return "Important Message";
}finally{
finallyHappensBeforeReturn();
}
}
public String unaffectedReference(){
String message = "Important msg";
try{
return message;
}finally{
message = " meaning of life";
}
}
public Container modifiedReference(){
Container c = new Container();
c.set("Important msg");
try{
return c;
}finally{
c.set("Meaning of life");
}
}
public void timer(){
try{
System.out.println("Try time = " + new Date().getTime());
}finally{
System.out.println("Finally time = " + new Date().getTime());
}
}
class Container{
String s;
void set(String s){
this.s = s;
}
String get(){
return s;
}
}
}
Если мы создадим основной метод следующим образом:
public static void main(String[] args){
TestClass instance = new TestClass();
instance.timer();
}
Мы можем ясно видеть вывод, который предполагает, что try происходит раньше, чем finally, как мы и ожидали. Для большинства из нас печатать время бессмысленно, так как на моей, а также на большинстве других машин метод будет выполняться менее чем за миллисекунду, но, тем не менее, я решил включить его.
Если мы изменим main на
public static void main(String[] args){
TestClass instance = new TestClass();
System.out.println(instance.unaffectedReference());
}
мы получаем напечатанное «Важное сообщение», что предполагает, что unaffectedReference() возвращает ссылку на строковый литерал «Важное сообщение», мы печатаем его в консоль, и только после этого указатель изменяется, чтобы указывать на объект String «Смысл жизни». Пока имеет смысл.
Однако, если мы изменим main на
public static void main(String[] args){
TestClass instance = new TestClass();
System.out.println(instance.modifiedReference().get());
}
получаем "Смысл жизни". Обратите внимание, что мы не сохраняем ссылку на возвраты ContainermodifiedReference(). Итак, если бы это было
public static void main(String[] args){
TestClass instance = new TestClass();
Container container = instance.modifiedReference();
System.out.println(container.get());
}
это имело бы смысл. modifierReference() возвращает ссылку, затем переходит в finally{}, меняет объект на ссылку, ну и ссылки - и только потом печатается значение. Что там произошло? наконец, выполняется до System.out.print(), но ПОСЛЕ возврата? Как это возможно?
И, последний пример -
public static void main(String[] args){
TestClass instance = new TestClass();
System.out.println(instance.finallyHappensBeforeReturn());
}
В этом случае мы получаем StackOverflowError, что также говорит о том, что finally происходит перед возвратом. Обратите внимание, что «Важное сообщение» никогда не печатается до того, как будет выдано исключение.
Итак, вопрос в том, что было раньше - наконец или возвращение?