Google

May 1, 2012

Core Java Interview Questions and Answers: String concatenation

It is a very common beginner level question on String concatenation. Its imperative to understand that NOT all String concatenations are  bad. It depends on how you are using it. You need to have the basic understanding that in Java, String is an immutable object and StringBuilder (not thread-safe) and StringBuffer (thread-safe) are mutable. In, Java you can concatenate strings a number of ways with the "+" operator, using the append( ) in StringBuilder and StringBuffer classes, and the other methods like concat( ) in String class.

Q1. Is anything wrong with the following code?

public class StringConcat {
    public static String withStringBuilder(int count) {
     String s = "Hello" + " " + " peter " + count;
     return s; 
    }

}
 
A1. No, the compiler internally uses a StringBuilder to use two append( ) calls to append the string and converts it to a String object using the toString( ) method.

Note: you can try the javap command  described below to see why.


Q2. Is anything wrong with the following code?
public class StringConcat {
    public static String withStringBuilder() {
      String s = "Hello" + " " + " peter " + " how are you";
      return s; 
    }

}
 
A2. No, the compiler is smart enough to work out that it is a static concatenation and it uses its optimization to concatenate the string during compile-time. If you verify this by using a Java decompiler like jd-gui.exe to decompile the compiled class back, you will get the source code as below.
 
public class StringConcat
 {
  public static String withStringBuilder(int count)
  {
    String s = "Hello  peter  how are you";
    return s;
  }
}

You can also use the javap command to dissemble the compiled class file using the following command
 
C:\workspaces\proj\Test\src>javap -c StringConcat

Gives the following output
 
Compiled from "StringConcat.java"
public class StringConcat extends java.lang.Object{
public StringConcat();
  Code:
   0:   aload_0
   1:   invokespecial       #1; //Method java/lang/Object."<init>":()V
   4:   return

public static java.lang.String withStringBuilder(int);
  Code:
   0:   ldc                 #2; //String Hello  peter  how are you
   2:   astore_1
   3:   aload_1
   4:   areturn

}

The line 0 shows that it has been optimized


Q3. Is anything wrong with the following code snippet

public class StringConcat {
 
 public static String withoutStringBuilder(int count) {
        String str = "";
        for (int i = 0; i < count; i++) {
            str += i;
        }

        return str;
    }
 
}
 
A3. Yes. it consumes more memory and can have performance implications. This is because, a String object in Java is immutable. This means, you can't modify a String. If the value of count is 100, then the above code will create 100 new StringBuilder objects, of which 99 of them will be discarded for garbage collection. Creating new objects unnecessarily is not efficient, and the garbage collector needs to clean up those unreferenced 99 objects. StringBuffer and StringBuilder: are mutable and use them when you want to modify the contents. StringBuilder was added in Java 5 and it is identical in all respects to StringBuffer except that it is not synchronized, which makes it slightly faster at the cost of not being thread-safe. The code below creates only two new objects, the StringBuilder and the final String that is returned.
public class StringConcat {
 
    public static String withStringBuilder(int count) {
        StringBuilder sb = new StringBuilder(100);
        for (int i = 0; i < count; i++) {
            sb.append(i);
        }

        return sb.toString();
    }

}
 
Now, if you want to be more pedantic as to how we know that the 100 StringBuilder objects are created, we can use the javap option to our rescue. The javap is a class file dissembler. If you compile the codebase in the question and then run the javap command with the StringConcat.class file as shown below
C:\workspaces\proj_blue\Test\src>javap -c StringConcat

You will get an output as shown below
 
Compiled from "StringConcat.java"
public class StringConcat extends java.lang.Object{
public StringConcat();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static java.lang.String withoutStringBuilder(int);
  Code:
   0:   ldc     #2; //String
   2:   astore_1
   3:   iconst_0
   4:   istore_2
   5:   iload_2
   6:   iload_0
   7:   if_icmpge       35
   10:  new     #3; //class java/lang/StringBuilder
   13:  dup
   14:  invokespecial   #4; //Method java/lang/StringBuilder."<init>":()V
   17:  aload_1
   18:  invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   21:  iload_2
   22:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   25:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   28:  astore_1
   29:  iinc    2, 1
   32:  goto    5
   35:  aload_1
   36:  areturn

}

The dissembled looks cryptic, but if you inspect it carefully the code within the public static java.lang.String withoutStringBuilder(int);

Line 5 to 32: is the code within the for loop. The "goto 5" indicates looping back.
Line 10: creates a new StringBuilder object every time
Line 18: uses the StringBuilder's append method to concatenate the String.
Line 25: uses the toString( ) method to convert the StringBuilder back to the existing String reference via toString( ) method.

If you run the improved code snippet in the answer through javap, you get the following output
Compiled from "StringConcat.java"
public class StringConcat extends java.lang.Object{
public StringConcat();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static java.lang.String withStringBuilder(int);
  Code:
   0:   new     #2; //class java/lang/StringBuilder
   3:   dup
   4:   bipush  100
   6:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":(I)V
   9:   astore_1
   10:  iconst_0
   11:  istore_2
   12:  iload_2
   13:  iload_0
   14:  if_icmpge       29
   17:  aload_1
   18:  iload_2
   19:  invokevirtual   #4; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
   22:  pop
   23:  iinc    2, 1
   26:  goto    12
   29:  aload_1
   30:  invokevirtual   #5; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   33:  areturn

}

As you could see

Line 0 to 6: initializes one StringBuilder object outside the for loop.
Line 12 to 26: is the for loop.
Line 19: indicates that since the StringBuilder is mutable, the string is appended via the append method.


Important: The creation of extra strings is not limited to the overloaded mathematical operator "+", but there are several other methods like concat( ), trim( ), substring( ), and replace( ) in the String class that generate new string instances. So use StringBuffer or StringBuilder for computation intensive operations to get better performance. Experiment with javap for the String methods like concat( ), trim( ), substring( ), and replace( ) .

Note: So, javap and jd-gui.exe are handy tools for debugging your application for certain issues. For example, the java decompiler is handy for debugging generics to see how the java source code with generics is converted after compilation by decompiling the .class file back to source code.

Labels:

13 Comments:

Blogger Jeetu said...

very good explanations

2:53 PM, June 28, 2012  
Blogger Arulkumaran Kumaraswamipillai said...

Thanks.

3:03 PM, June 28, 2012  
Blogger Gaurav said...

very detailed and still to the point explanation.

12:34 AM, June 30, 2012  
Anonymous Anonymous said...

Awesome :)

3:24 AM, August 03, 2012  
Anonymous Anonymous said...

Very helpful

4:42 AM, August 09, 2012  
Anonymous Anonymous said...

Thks

9:35 PM, September 14, 2012  
Blogger Victor0110 said...

Thanks a lot... That was helpful

4:42 AM, September 28, 2012  
Blogger sumit mishra said...

Answer to question Q2 is wrong. Java is a strictly typed language. If no argument is passing to the function it should be declared void as input parameter.

12:34 AM, November 08, 2012  
Anonymous Anonymous said...

Thanks for this explanation.

11:50 PM, September 04, 2013  
Anonymous Anonymous said...

Very Good.

2:34 PM, November 15, 2013  
Anonymous Anonymous said...

very good explanation

4:51 AM, February 20, 2014  
Anonymous Anonymous said...

Great Explanation

2:28 PM, March 21, 2014  
Anonymous Anonymous said...

grt explanation, you are doing good job

6:16 PM, April 12, 2014  

Post a Comment

Subscribe to Post Comments [Atom]

Links to this post:

Create a Link

<< Home