Monday, February 10, 2014

Best Practices Java - StringBuffer Part 2

It's good to define string as StringBuffer for most of the common use(Refer Part 1). We will now see how StringBuffer enlarge itself, as it is mutable.

If you are just calling the default creation of StringBuffer, the following code will get called(default size of 16 characters).
   super(16);
}



StringBuffer takes its data structure from its parent class which is AbstractStringBuilder, something like:


abstract class AbstractStringBuilder implements AppendableCharSequence {
            char value[]; // actual character storage.
int count; // count the no. of char's used.



This is how expandCapacity has been written in JDK:


void expandCapacity(int minimumCapacity) {
 int newCapacity = (value.length + 1) * 2;
 if (newCapacity < 0) {
  newCapacity = Integer.MAX_VALUE;
 } else if (minimumCapacity > newCapacity) {
  newCapacity = minimumCapacity;
 }
 value = Arrays.copyOf(value, newCapacity);
}




This expandCapacity() has been called from append() method of StringBuffer. Most of the methods of StringBuffer are synchronized as expected.

For more understanding, you can see the openJDK source code. 

 


Saturday, February 08, 2014

Best Practices Java - StringBuffer

It's been 3 years when I have not done any blogging here. Some day before, one of my friends was asking me about StringBuffer and he has the point that I don't have any justification that why Sun has created StringBuffer.

I am writing this blog from a very rural village of Bihar, India. The common problem I found was people are not utilizing the time in best of work. Many of the kids go to the market to bring one-one item at a time. Alright, are we engineers also follow the same trend.

We use String as default and then we keep adding things in it. Something like:

String dontUse = "This";
dontUse +="is not right";

Alright, here is a small code I have written to understand the estimated time.

public class StringBufferExample {

public static void main(String[] args) {

String[] dontUse = new String[10000];
                //StringBuffer[] dontUse = new StringBuffer[10000];
for(int i=0;i<10000;i++) { }
long startTime = System.nanoTime();
for(int i=0;i<10000;i++) {
                        dontUse[i]= new String("this");
// dontUse[i]= new StringBuffer("this");
}
for(int i=0;i<10000;i++) {
                        dontUse[i]+="is wrong";
// dontUse[i].append("is wrong");
}
long endTime = System.nanoTime();
System.out.println(endTime - startTime);

}
}

Approx Time taken from this code: 5501435(ns) whereas if you run the commented code, it will take: 2258812(ns)
So, not visible but normal String operation for "simply" addition of two string is "twice" costlier than StringBuffer.

Running: javap -c -classpath . StringBufferExample (copying those lines which are costly), will clearly tell you why String operation is a costly affair(actually it was never a String operation, it changes things to StringBuffer and then again convert it by toString to String).


   64:  if_icmpge       97
   67:  new     #6; //class java/lang/StringBuilder
   70:  dup
   71:  invokespecial   #7; //Method java/lang/StringBuilder."<init>":()V
   74:  aload_1
   75:  iload   4
   77:  dup2_x1
   78:  aaload
   79:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
   82:  ldc     #9; //String is wrong
   84:  invokevirtual   #8; //Method java/lang/StringBuilder.append:(Ljava/lang/
String;)Ljava/lang/StringBuilder;
   87:  invokevirtual   #10; //Method java/lang/StringBuilder.toString:()Ljava/l
ang/String;
   90:  aastore


Now in the next blog, I will cover how StringBuffer handles the capacity, how it enlarge its capacity and when. It's a pretty simple code written in JDK.