views:

85

answers:

2

Guys, help me clarify. Say i have the following line in my program:

jobSetupErrors.append("abc");

In the case above where jobSetupErrors is a StringBuilder(), what i see happen is:

  1. New String Object is created and assigned value "abc"
  2. value of that String object is assigned to the existing StringBuilder object

If that is correct, and I add 1 more line ...

jobSetupErrors.append("abc");
logger.info("abc");

In the above example are we creating String object separately 2 times?

If so, would it be more proper to do something like this?

String a = "abc";
jobSetupErrors.append(a);
logger.info(a);

Is this a better approach? Please advise

+8  A: 

In the above example are we creating String object separately 2 times?

No, because in Java String literals (anything in double-quotes) are interned. What this means is that both of those lines are referring to the same String, so no further optimization is necessary.

In your second example, you are only creating an extra reference to the same String, but this is what Java has already done for you by placing a reference to it in something called the string pool. This happens the first time it sees "abc"; the second time, it checks the pool and finds that "abc" already exists, so it is replaced with the same reference as the first one.

See http://en.wikipedia.org/wiki/String_interning for more information on String interning.

danben
+4  A: 

To help find out, I wrote a class like the following:

class Test {
  String a = "abc" ;
  StringBuilder buffer = new StringBuilder() ;

  public void normal() {
    buffer.append( "abc" ) ;
    buffer.append( "abc" ) ;
  }

  public void clever() {
    buffer.append( a ) ;
    buffer.append( a ) ;
  }
}

If we compile this, and then run javap over it to extract the bytecode:

14:09:58 :: javap $ javap -c Test
Compiled from "Test.java"
class Test extends java.lang.Object{
java.lang.String a;

java.lang.StringBuilder buffer;

Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   ldc #2; //String abc
   7:   putfield    #3; //Field a:Ljava/lang/String;
   10:  aload_0
   11:  new #4; //class java/lang/StringBuilder
   14:  dup
   15:  invokespecial   #5; //Method java/lang/StringBuilder."<init>":()V
   18:  putfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   21:  return

public void normal();
  Code:
   0:   aload_0
   1:   getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   4:   ldc #2; //String abc
   6:   invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   9:   pop
   10:  aload_0
   11:  getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   14:  ldc #2; //String abc
   16:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  pop
   20:  return

public void clever();
  Code:
   0:   aload_0
   1:   getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   4:   aload_0
   5:   getfield    #3; //Field a:Ljava/lang/String;
   8:   invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   11:  pop
   12:  aload_0
   13:  getfield    #6; //Field buffer:Ljava/lang/StringBuilder;
   16:  aload_0
   17:  getfield    #3; //Field a:Ljava/lang/String;
   20:  invokevirtual   #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   23:  pop
   24:  return

}

We can see 2 things.

First, the normal method is using the same String instance for both of those calls (indeed it is the same literal as is set to the a member variable of this class in the initialisation block)

And secondly, the clever method is longer than the normal one. This is because extra steps are required to fetch the property out of the class.

So the moral of the story is that 99% of the time, Java does things the right way on it's own, and theres no need in trying to be clever ;-) (and javap is a really cool tool for when you want to know exactly what's going on)

tim_yates
javap, not jsonp.
danben
whoops! ;-) can you tell what I'm *supposed* to be doing? ;-)
tim_yates
you should use a local variable instead of a field in `clever` if comparing the length of code; but anyway, the question was mainly about creating Strings and, as can be seen by your example, there is only one String object involved!
Carlos Heuberger
With a local variable, `clever` is still longer, as you have an additional `astore_1` operation to get the interned String into the variable
tim_yates