user1825817
user1825817

Reputation:

new String() vs literal string performance

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

Answers (4)

Marko Topolnik
Marko Topolnik

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

pcalcao
pcalcao

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

Michael
Michael

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

sam
sam

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

Related Questions