Reputation: 5165
Found this question here
And I can't understand, why on first case it prints CoolReturn+1
and on second case CoolReturn
? How does it work?
Thanks
====================
What will be printed?
public void testFinally(){
System.out.println(setOne().toString());
}
protected StringBuilder setOne(){
StringBuilder builder=new StringBuilder();
try{
builder.append("Cool");
return builder.append("Return");
}finally{
builder.append("+1");
}
}
Answer: CoolReturn+1
A bit more difficult:
public void testFinally(){
System.out.println(setOne().toString());
}
protected StringBuilder setOne(){
StringBuilder builder=new StringBuilder();
try{
builder.append("Cool");
return builder.append("Return");
}finally{
builder=null; /* ;) */
}
}
Answer: CoolReturn
Upvotes: 7
Views: 751
Reputation: 23208
This works because the return
expression is evaluated before the finally
block is executed. This is pretty apparent when you invoke a method in the return
statement of your code and add logging statements to your try
and finally
blocks. The relevant explanation can be found in the JLS 3rd edition, 14.20.2. This is one of the reasons why return
statements in the finally
block produce a warning in IDE's like Eclipse.
A sample groovy code:
def doSomething() {
def f = "something";
try {
return f += doSomethingMore()
} finally {
println "before nulling";
f = null;
println "after nulling";
}
}
def doSomethingMore() {
println "doSomethingMore called"
return "-wow";
}
println "output from call ---> " + doSomething()
Upvotes: 1
Reputation: 82559
The first one:
The finally will always fire (assuming the machien doesn't crash or anything). So after the return, the finally block fires, and since it has a reference to the object "builder", it appends the extra token to it.
The second one:
The finally block fires just like before, but it sets the reference to builder to be null. The object still exists, because it still has a link to it.
Upvotes: 6
Reputation: 476
In the first example, in the finally block, you manipulate the string builder with append.
In the second example, in the finally block, you change your pointer to the string builder to be the null pointer, after you return the result from the append method. This does not modify the string builder that you formerly pointed to in any way.
EDIT: Looks like I got beat to it.
Upvotes: 1
Reputation: 28693
Consider
protected StringBuilder setOne(){
StringBuilder builder=new StringBuilder();
try{
builder.append("Cool");
return builder.append("Return");
}finally{
builder.append("+1");
}
}
as
protected StringBuilder setOne(){
StringBuilder builder=new StringBuilder();
try{
builder.append("Cool");
StringBuilder ret = builder.append("Return"); // 1
return ret; // 2
}finally{
builder.append("+1"); //3
}
}
line 1 is executed, the builder
is returned as result. Then line 3 is executed, and the builder
gets appended by +1
, then the ret
is returned which is a "reference" to the object referenced by builder
. The same is for the second case. Hope it is clear.
Upvotes: 7
Reputation: 61526
When it does return builder.append("Return") a copy of the reference to the builder variable is pushed onto the stack. Then builder is set to null. The caller then pops the copy of the reference off the stack.
Upvotes: 2
Reputation: 5098
The finally block will always execute. http://download.oracle.com/javase/tutorial/essential/exceptions/finally.html Thats why all three statements are appending.
Upvotes: 0
Reputation: 10790
The finally operator always runs so builder gets returned and then the +1 is returned.
On the second one, the builder is set to null, so there is nothing else to add to it. It could just as easily be builder = "" in the last one.
Upvotes: 0