开发者

Is there a "fastest way" to construct Strings in Java?

开发者 https://www.devze.com 2022-12-13 08:26 出处:网络
I normally create a String in Java the following way: String foo = \"123456\"; However, My lecturer has insisted to me that forming a String using the format method, as so:

I normally create a String in Java the following way:

String foo = "123456";

However, My lecturer has insisted to me that forming a String using the format method, as so:

String foo = String.format("%s", 123456);

Is much faster.

Also, he says that using the StringBuilder class is even faster.

StringBuilder sb = new StringBuilder();
String foo = s开发者_JAVA百科b.append(String.format("%s", 123456)).toString();

Which is the fastest method to create a String, if there even is one?

They could not be 100% accurate as I might not remember them fully.


If there is only one string then:

String foo = "123456";

Is fastest. You'll notice that the String.format line has "%s%" declared in it, so I don't see how the lecturer could possibly think that was faster. Plus you've got a method call on top of it.

However, if you're building a string over time, such as in a for-loop, then you'll want to use a StringBuilder. If you were to just use += then you're building a brand new string every time the += line is called. StringBuilder is much faster since it holds a buffer and appends to that every time you call append.


Slightly off-topic, but I wish that the whole "must-not-use-plus-to-concatenate-strings-in-Java" myth would go away. While it might have been true in early versions of Java that StringBuffer was faster and "+ was evil", it is certainly not true in modern JVMs that are taking care of a lot of optimisations.

For example, which is faster?

String s = "abc" + "def";

or

    StringBuffer buf = new StringBuffer();
    buf.append("abc");
    buf.append("def");
    String s = buf.toString();

The answer is the former. The JVM recognises that this is a string constant and will actually put "abcdef" in the string pool, whereas the "optimised stringbuffer" version will cause an extra StringBuffer object to be built.

Another JVM optimisation is

String s = onestring + " concat " + anotherstring;

Where the JVM will work out what the best way of concatenating will be. In JDK 5, this means a StringBuilder will be internally used and it will be faster than using a string buffer.

But as other answers have said, the "123456" constant in your question is certainly the fastest way and your lecturer should go back to being a student :-)

And yes, I've been sad enough to verify this by looking at the Java bytecode...


This whole discussion is moot. Please read this article by Jeff, i.e., the guy who created Stack Overflow.

The Sad Tragedy of Micro-Optimization Theater

Please refer your instructor to this post and ask him to stop ruining his/her student's brains with useless information. Algorithmic optimizations are where your code will live or die, not with what method you use to construct strings. In any case, StringBuilder, and String formatter have to execute ACTUAL CODE with REAL MEMORY, if you just construct a string it gets set aside during compile time and is ready to be used when you need it, in essence, it has 0 run-time cost, while the other options have real cost, since code actually needs to be executed.


String foo = "some string literal";

Is certainly the fastest way to make a String. It's embedded in the .class file and is a simple memory look-up to retrieve.

Using String.format when you have nothing to really format just looks ugly and might cause junior developers to cry.

If the String is going to be modified, then StringBuilder is the best since Strings are immutable.


In your second example, using:

String foo = String.format("%s", 123456);

doesn't buy you anything; 123456 is already a constant value, so why not just assign foo = "123456"? For constant strings, there's no better way.

If you're creating a string from multiple parts being appended together at runtime, use StringBuffer or StringBuilder (the former being thread-safe).


If your string is known at compile-time, then using a literal is best: String foo = "123456";.

If your string is not known at compile-time and is composed of an aggregation of smaller strings, StringBuilder is usually the way to go (but beware thread-safety!).

Using String foo = String.format("%s", 123456); could reduce your .class' size and make class-loading it a tiny bit faster, but that would be extremely aggressive (extreme) memory tuning there ^^.


As has been pointed out, if you're just building a single string with no concatenation, just use String.

For concatenating multiple bits into one big string, StringBuffer is slower than StringBuilder, but StringBuffer is synchronized. If you don't need synchronization, StringBuilder.


Are you 100% certain that the instructor was not talking about something like:

String foo = "" + 123456;

I see my students do that type of thing "all the time" (a handful will do that each term). The reason that they do it is that some book showed them how to do it that way. Shakes head and fist at lazy book writers!


The first example you gave is the fastest and the simplest. Use that.

Each piece of code you added in those examples makes it significantly slower and more difficult to read.

I would suggest example 2 is at least 10-100x slower than example 1 and example 3 is about 2x slower than example 2.

Did your processor provide any justification for this assertion?

BTW: Your first example doesn't construct a String at all (which is why it is fastest), it just hands you a String sitting in the String constant pool.


How about measuring dynamic strings so that VM cannot optimise it:

public static void measureConcats(long lim){
double sum = 0;
long start = System.currentTimeMillis();
for(long a = 0;a<lim;++a){
    sum+=Math.random();
}
long end = System.currentTimeMillis();
System.out.println("Sum:" +sum);
System.out.println("Double creations time:" + (end - start));

String res = "";
Double sad = 0.0;
start = System.currentTimeMillis();
for(long b = 0;b<lim;++b){
    sad = Math.random();
    String sa = sad.toString();
    res+=sa;
}
end = System.currentTimeMillis();
System.out.println("Pure string concat time:" + (end - start));
System.out.println("len:"+res.length());

StringBuffer sbf = new StringBuffer();
start = System.currentTimeMillis();
for(long c = 0;c<lim;++c){
    sad = Math.random();
    String sa = sad.toString();
    sbf.append(sa);
}
end = System.currentTimeMillis();
System.out.println("StringBuffer concat time:" + (end - start));
System.out.println("len:"+sbf.length());}

My result for 10000 concats is 364ms for String+=String and 14ms for StringBuffer append. I was very surprised about this result.

0

精彩评论

暂无评论...
验证码 换一张
取 消