Why StringBuilder does not print what it should print in a small code
public final class Test1 {
public void test() {
System.out.println(setFin().toString());
}
protected StringBuilder setFin() {
StringBuilder builder = new StringBuilder();
try {
builder.append("John");
return builder.append("Ibrahim");
} finally {
System.out.println("In finaly"); // builder.append("-DarElBeida");
builder = null;
}
}
public static void main(String args[]){
new Test1().test();
}
}
In the last statement executed in setFin()
(in the finally
block) I have assigned null
to builder
, but my code prints "In finally"
and then "JohnIbrahim"
. Can anybody explain to me what is going on here?
When there is a return
statement inside the try
block, it will execute the finally
block before actually returning.
And the method doesn't return null
because the return
statement holds a reference to the actual StringBuilder object, not to the variable builder
.
Setting builder == null
doesn't delete the StringBuilder itself, it just drops builder
's reference to it.
This behavior can be confusing. To make things clear it could be helpful to return from outside the try/catch/finally block:
StringBuilder builder = new StringBuilder();
try {
builder.append("John");
builder.append("Ibrahim");
} finally {
System.out.println("In finaly"); // builder.append("-DarElBeida");
builder = null;
}
return builder;
You are returning builder
. After that you set builder
to null. But it has already been returned. It does not matter what you do to the variable afterwards. The return value is already "locked-in". What you could do is mess with the object that is being returned. For example, builder.setLength(0)
will remove all text to it.
In theory, you could also return null
from the finally block, but that (changing the return value) is highly discouraged.
Return value is evaluated and stored on the stack , before the finally
block runs. Note that the value on the stack is actually the value of the StringBuilder
reference. So, even if you set the builder
to null
, that doesn't changes the evaluated return
value already on the stack. However, if the return value is a reference to an mutable object, you can mutate the object, and the changes will be visible in return
value.
For eg, if you add the below statement in the finally
block instead of nullifying
the reference:
builder.append("Hrithik Roshan");
then you will see that content in the return value.
However, if you return
the builder
again, from finally
block, it will overright the previous evaluated return
statement. But mind you it's not a good idea.
finally
is always executed, unless the JVM crashes or exits before the try
block finishes.
If the try
block completes due to a return
statement, the expression of the return
is evaluated into a single value before the finally
block executes. That value is saved, and returned when the finally
block completes.
Thus, the assignment of builder = null
has no effect because the evaluation of builder.append("Ibrahim")
is already finished by the time the finally
executes.
builder
holds a reference to the StringBuilder that you've created. When you do builder = null
, you're setting builder
to no longer hold that reference. The StringBuilder itself still exists (at least until garbage collection occurs).
What's happening is that your return
statement is returning a reference to the StringBuilder. It's not returning the variable builder
; it's returning a reference to the thing that builder
refers to. So even though you're wiping out the variable, the return statement already has a reference to the created object.
If you printed builder
in your finally
block, it would be null there.
First executed return
statement which execute builder.append("Ibrahim")
that returns the reference of StringBuilder
. The referece is saved to the stack. Then excuted the finally
block. You have nulled the local variable, but the reference to StringBuilder
object passed to the caller after the method actually return. That's why printed all values. The error is that you assign a value to the builder
in finally
block that is never used. The stack keeps the value of the return
statement operand before it actually returned, ie after finally
block. If you don't want to return reference from the method you should return null
in the finally
block, that will override the value in the stack.
} finally {
System.out.println("In finaly"); // builder.append("-DarElBeida");
return null;
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.