performance - StringBuffer and String usage scenario in Java -
i can implement single method in 2 ways,
1.
public string gettestmessage() { return "hello" + "world..!"; }
2.
public string gettestmessage() { return new stringbuffer("hello").append("world..!").tostring(); }
in first scenario, there 2 new string
objects created.
in second scenario there 2 new objects created, there 1 string
, stringbuffer
. way fast them? little bit confused.
between 2 scenarios, option 1 faster every time, unless jitc don't expect. really don't expect make difference, though, unless call methods extremely frequently.
why? because don't create new objects option 1. compiler should perform constant folding, turning "hello" + "world..!"
"helloworld..!"
. , because compile-time constant string
, it's automatically interned string
pool @ vm startup. every time method called, you're getting reference "canonical" string
. no object creation performed.
in option 2, create multiple objects -- stringbuffer
(you should using stringbuilder
, way), backing char[]
, , result string
(at least). , doing in tight loop not efficient.
in addition, option 1 more readable, should consider when writing code.
proof:
given test code:
public class test { public string gettestmessagea() { return "hello" + "world..!"; } public string gettestmessageb() { return new stringbuffer("hello").append("world..!").tostring(); } }
compiling javac -xd-printflat
shows code processed before compilation bytecode:
public class test { public test() { super(); } public string gettestmessagea() { return "helloworld..!"; } public string gettestmessageb() { return new stringbuffer("hello").append("world..!").tostring(); } }
notice how "hello" + "world..!"
converted at compile time single string
. string
concatenation not happening in first option.
now let's @ bytecode. here's constant pool:
constant pool: #1 = methodref #10.#20 // java/lang/object."<init>":()v #2 = string #21 // helloworld..! #3 = class #22 // java/lang/stringbuffer #4 = string #23 // hello #5 = methodref #3.#24 // java/lang/stringbuffer."<init>":(ljava/lang/string;)v #6 = string #25 // world..! #7 = methodref #3.#26 // java/lang/stringbuffer.append:(ljava/lang/string;)ljava/lang/stringbuffer; #8 = methodref #3.#27 // java/lang/stringbuffer.tostring:()ljava/lang/string;
here's bytecode option 1:
public java.lang.string gettestmessagea(); code: 0: ldc #2 // string helloworld..! 2: areturn
well, that's short. can see, jvm loads constant (ldc
) pool , returns it. no object created directly in method.
now here's bytecode option 2:
public java.lang.string gettestmessageb(); code: 0: new #3 // class java/lang/stringbuffer 3: dup 4: ldc #4 // string hello 6: invokespecial #5 // method java/lang/stringbuffer."<init>":(ljava/lang/string;)v 9: ldc #6 // string world..! 11: invokevirtual #7 // method java/lang/stringbuffer.append:(ljava/lang/string;)ljava/lang/stringbuffer; 14: invokevirtual #8 // method java/lang/stringbuffer.tostring:()ljava/lang/string; 17: areturn
so code creates new stringbuffer
, loads appropriate constants string pool, calls append()
method each of them, calls tostring()
method on buffer. tostring()
implemented such:
@override public synchronized string tostring() { if (tostringcache == null) { tostringcache = arrays.copyofrange(value, 0, count); } return new string(tostringcache, true); }
so option 2 create 2 new objects every time call it, , executes more instructions. thus, option 1 faster.
Comments
Post a Comment