When doing concatenating lots of strings, I have been recommended to do it using a StringBuilder
as such:
StringBuilder someString = new StringBuilder("abc"); someString.append("def"); someString.append("123"); someString.append("moreStuff");
as opposed to
String someString = "abc"; someString = someString + "def"; someString = someString + "123"; someString = someString + "moreStuff";
which would result in the creation of quite a few Strings, as opposed to one.
Now, I need to do a similar thing, but instead of using concatenation I use the replace
method of String as such:
String someString = SOME_LARGE_STRING_CONSTANT; someString = someString.replace("$VARIABLE1", "abc"); someString = someString.replace("$VARIABLE2", "def"); someString = someString.replace("$VARIABLE3", "123"); someString = someString.replace("$VARIABLE4", "moreStuff");
To accomplish the same thing using StringBuilder, I have to do this, just for one replace:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
So my question is: "Is it better to use String.replace and have lots of extra Strings created, or to use StringBuilder still, and have lots of long winded lines such as the one above?"
Replace() was faster by about 20% every time swapping out 8-10 letter words. Try it for yourself if you want your own empirical evidence.
If you are using two or three string concatenations, use a string. StringBuilder will improve performance in cases where you make repeated modifications to a string or concatenate many strings together. In short, use StringBuilder only for a large number of concatenations.
So from this benchmark test we can see that StringBuilder is the fastest in string manipulation. Next is StringBuffer , which is between two and three times slower than StringBuilder .
I think we should go with StringBuilder append approach. Reason being : The String concatenate will create a new string object each time (As String is immutable object) , so it will create 3 objects. With String builder only one object will created[StringBuilder is mutable] and the further string gets appended to it.
It is true that StringBuilder tends to be better than concatenating or modifying Strings manually, since StringBuilder is mutable, while String is immutable and you need to create a new String for each modification.
Just to note, though, the Java compiler will automatically convert an example like this:
String result = someString + someOtherString + anotherString;
into something like:
String result = new StringBuilder().append(someString).append(someOtherString).append(anotherString).toString();
That said, unless you're replacing a whole lot of Strings, go for whichever is more readable and more maintainable. So if you can keep it cleaner by having a sequence of 'replace' calls, go ahead and do that over the StringBuilder method. The difference will be negligible compared to the stress you save from dealing with the sad tragedy of micro-optimizations.
PS
For your code sample (which, as OscarRyz pointed out, won't work if you have more than one "$VARIABLE1"
in someString
, in which case you'll need to use a loop), you could cache the result of the indexOf
call in:
someString.replace(someString.indexOf("$VARIABLE1"), someString.indexOf("$VARIABLE1")+10, "abc");
With
int index = someString.indexOf("$VARIABLE1"); someString.replace(index, index+10, "abc");
No need to search the String twice :-)
Guess what? If you are running with Java 1.5+ the concatenation works the same with string literals
String h = "hello" + "world";
and
String i = new StringBuilder().append("hello").append("world").toString();
Are the same.
So, the compiler did the work for you already.
Of course better would be:
String j = "hellworld"; // ;)
As for the second, yeap, that's preferred, but should't be that hard, with the power of "search and replace" and a bit of regex foo
For instance you can define a method like the one in this sample:
public static void replace( String target, String replacement, StringBuilder builder ) { int indexOfTarget = -1; while( ( indexOfTarget = builder.indexOf( target ) ) >= 0 ) { builder.replace( indexOfTarget, indexOfTarget + target.length() , replacement ); } }
And your code currently looks like this:
someString = someString.replace("VARIABLE1", "abc"); someString = someString.replace("VARIABLE2", "xyz");
All you have to do is grab text editor an trigger something like this vi search and replace:
%s/^.*("\(.*\)".\s"\(.*\)");/replace("\1","\2",builder);
That read: "take anything in parenthesis and that looks like a string literal, and put it in this other string".
And your code will look from this:
someString = someString.replace("VARIABLE1", "abc"); someString = someString.replace("VARIABLE2", "xyz");
to this:
replace( "VARIABLE1", "abc", builder ); replace( "VARIABLE2", "xyz", builder );
In no time.
Here's a working demo:
class DoReplace { public static void main( String ... args ) { StringBuilder builder = new StringBuilder( "LONG CONSTANT WITH VARIABLE1 and VARIABLE2 and VARIABLE1 and VARIABLE2"); replace( "VARIABLE1", "abc", builder ); replace( "VARIABLE2", "xyz", builder ); System.out.println( builder.toString() ); } public static void replace( String target, String replacement, StringBuilder builder ) { int indexOfTarget = -1; while( ( indexOfTarget = builder.indexOf( target ) ) > 0 ) { builder.replace( indexOfTarget, indexOfTarget + target.length() , replacement ); } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With