Saturday, July 1, 2017

Strings in Java are immutable

Concatenating Strings means appending one string to another. Strings in Java are immutable meaning they cannot be changed once created. Therefore, when concatenating two Java String objects to each other, the result is actually put into a third String object.
Here is a Java String concatenation example:
String one = "Hello";
String two = "World";

String three = one + " " + two;
The content of the String referenced by the variable three will be Hello World; The two other Strings objects are untouched.

String Concatenation Performance

When concatenating Strings you have to watch out for possible performance problems. Concatenating two Strings in Java will be translated by the Java compiler to something like this:
String one = "Hello";
String two = " World";

String three = new StringBuilder(one).append(two).toString();
As you can see, a new StringBuilder is created, passing along the first String to its constructor, and the second String to its append() method, before finally calling the toString() method. This code actually creates two objects: A StringBuilder instance and a new String instance returned from the toString() method.
When executed by itself as a single statement, this extra object creation overhead is insignificant. When executed inside a loop, however, it is a different story.
Here is a loop containing the above type of String concatenation:
String[] strings = new String[]{"one", "two", "three", "four", "five" };

String result = null;
for(String string : strings) {
    result = result + string;
}
This code will be compiled into something similar to this:
String[] strings = new String[]{"one", "two", "three", "four", "five" };

String result = null;
for(String string : strings) {
    result = new StringBuilder(result).append(string).toString();
}
Now, for every iteration in this loop a new StringBuilder is created. Additionally, a String object is created by the toString() method. This results in a small object instantiation overhead per iteration: One StringBuilder object and one String object. This by itself is not the real performance killer though. But something else related to the creation of these objects is.
Every time the new StringBuilder(result) code is executed, the StringBuilder constructor copies all characters from the result String into the StringBuilder. The more iterations the loop has, the bigger the result String grows. The bigger the result String grows, the longer it takes to copy the characters from it into a new StringBuilder, and again copy the characters from the StringBuilder into the temporary String created by the toString() method. In other words, the more iterations the slower each iteration becomes.
The fastest way of concatenating Strings is to create a StringBuilder once, and reuse the same instance inside the loop. Here is how that looks:
String[] strings = new String[]{"one", "two", "three", "four", "five" };

StringBuilder temp  = new StringBuilder();
for(String string : strings) {
    temp.append(string);
}
String result = temp.toString();
This code avoids both the StringBuilder and String object instantiations inside the loop, and therefore also avoids the two times copying of the characters, first into the StringBuilder and then into a String again.
@reference_1_jenkov.com

No comments:

Post a Comment