Reputation:
This question has been asked many times on StackOverflow but none of them were based on performance.
In Effective Java book it's given that
If
String s = new String("stringette");
occurs in a loop or in a frequently invoked method, millions of String instances can be created needlessly.The improved version is simply the following:
String s = "stringette";
This version uses a single String instance, rather than creating a new one each time it is executed.
So, I tried both and found significant improvement in performance:
for (int j = 0; j < 1000; j++) {
String s = new String("hello World");
}
takes about 399 372 nanoseconds.
for (int j = 0; j < 1000; j++) {
String s = "hello World";
}
takes about 23 000 nanoseconds.
Why is there so much performance improvement? Is there any compiler optimization happening inside?
Upvotes: 19
Views: 23028
Reputation: 200168
The performance difference is in fact much greater: HotSpot has an easy time compiling the entire loop
for (int j = 0; j < 1000; j++)
{String s="hello World";}
out of existence so the runtime is a solid 0. This, however, happens only after the JIT compiler kicks in; that's what warmup is for, a mandatory procedure when microbenchmarking anything on the JVM.
This is the code I ran:
public static void timeLiteral() {
for (int j = 0; j < 1_000_000_000; j++)
{String s="hello World";}
}
public static void main(String... args) {
for (int i = 0; i < 10; i++) {
final long start = System.nanoTime();
timeLiteral();
System.out.println((System.nanoTime() - start) / 1000);
}
}
And this is a typical output:
1412
38
25
1
1
0
0
1
0
1
You can observe the JIT taking effect very soon.
Note that I don't iterate one thousand, but one billion times in the inner method.
Upvotes: 4
Reputation: 15990
In the first case, a new object is being created in each iteration, in the second case, it's always the same object, being retrieved from the String constant pool.
In Java, when you do:
String bla = new String("xpto");
You force the creation of a new String object, this takes up some time and memory.
On the other hand, when you do:
String muchMuchFaster = "xpto"; //String literal!
The String will only be created the first time (a new object), and it'll be cached in the String
constant pool, so every time you refer to it in it's literal form, you're getting the exact same object, which is amazingly fast.
Now you may ask... what if two different points in the code retrieve the same literal and change it, aren't there problems bound to happen?!
No, because Strings, in Java, as you may very well know, are immutable! So any operation that would mutate a String returns a new String, leaving any other references to the same literal happy on their way.
This is one of the advantages of immutable data structures, but that's another issue altogether, and I would write a couple of pages on the subject.
Edit
Just a clarification, the constant pool isn't exclusive to String types, you can read more about it here, or if you google for Java constant pool.
http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf
Also, a little test you can do to drive the point home:
String a = new String("xpto");
String b = new String("xpto");
String c = "xpto";
String d = "xpto";
System.out.println(a == b);
System.out.println(a == c);
System.out.println(c == d);
With all this, you can probably figure out the results of these Sysouts:
false
false
true
Since c
and d
are the same object, the ==
comparison holds true.
Upvotes: 41
Reputation: 2867
as already have been answered the second retrieves the instance from the String pool (remember Strings are immutable).
Additionally you should check the intern() method which enables you to put new String() into a pool in case you do not know the constant value of the string in runtime: e.g:
String s = stringVar.intern();
or
new String(stringVar).intern();
I will add additional fact, you should know that additionally to the String object more info exist in the pool (the hashcode): this enables fast hashMap search by String in the relevant data Strtuctures (instead of recreating the hashcode each time)
Upvotes: 1
Reputation: 118
The JVM maintains a pool of references to unique String objects that are literals. In your new String example you are wrapping the literals with an instance of each.
See http://www.precisejava.com/javaperf/j2se/StringAndStringBuffer.htm
Upvotes: 0