简体   繁体   中英

Why StringBuilder does not print?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM