Assuming that I need to initiate a String and then update it for a couple a times more, like in this pseudo code:
String s = "first";
if (<some condition>) { s += "second"; }
if (<some condition>) { s += "third"; }
if (<some condition>) { s += "fourth"; }
In case that I have about 4 times in maximum, is it better to use it that way or just simply use StringBuffer/StringBuilder ?
Actually what i'm asking is, in case of which updating times of a String (which is a mutable type) is the efficient way to use the above options?
First, String is not a mutable class. Every time you use +=
, another object is returned.
Second, unless you use that in a tight loop, it is not very important anyway.
Third, although it may not be a computer science-like approach, if I try to use
StringBuilder s = new StringBuilder("first");
s.append( "second" );
s.append( "third" );
s.append( "fourth" );
Intellij suggests to replace it with a String, and that suggestion only appears if it is at least as efficient to use a simple String (although it may not be exactly the same thing because of the conditions)
According to Java: String concat vs StringBuilder - optimised, so what should I do? the Java compiler does replace a series of String concatenations with String builders:
public static void main(String[] args) {
String s = "first";
s+=" second" ;
if(args.length >0)
s+=" third";
System.out.println("s, = " + s);
}
Using JDK 1.8.0_66 and using javap -c SbTest.class
the following output is produced. Although I am not an expert on byte code, it seems that multiple instances of StringBuilder
are created ( 3
, 28
). So as suggested in the linked answers, the compiled code seems to be something like:
String s = "first";
s = new StringBuilder().append(s).append(" second") ;
if(args.length >0)
s = new StringBuilder().append(s).append(" third") ;
So unless the JIT is optimizing this, it might still be more efficient to use the StringBuilder
yourself.
public static void main(java.lang.String[]);
Code:
0: ldc #2 // String first
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String second
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_1
23: aload_0
24: arraylength
25: ifle 48
28: new #3 // class java/lang/StringBuilder
31: dup
32: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
35: aload_1
36: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
39: ldc #8 // String third
41: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
44: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
47: astore_1
48: getstatic #9 // Field java/lang/System.out:Ljava/io/PrintStream;
51: new #3 // class java/lang/StringBuilder
54: dup
55: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
58: ldc #10 // String s, =
60: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
63: aload_1
64: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
67: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
70: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
73: return
String s = "first";
if (<some condition>) { s += "second"; }
if (<some condition>) { s += "third"; }
if (<some condition>) { s += "fourth"; }
Is the right approach because the compiler will turn it into a StringBuilder ( JDK 1.6 and above ) That said, the optimization is the same unless you are using it inside a loop.
See this link for more info
If you are working with reasonably sized strings (like the words you have there) using the string class is completely fine, and using a string builder class won't be much faster than using a normal string. You want to replace it when you might be dealing with huge strings (think many many paragraphs) and repeatedly changing them. StringBuilder and StringBuffer should work about the same, but StringBuffer is thread safe, so if you are going to write multithreaded code then use StringBuffer.
The only way to know is to benchmark.
package com.example;
import static org.junit.Assert.*;
import java.time.Duration;
import java.time.Instant;
import org.junit.Test;
public class ExampleTest {
@Test
public void test() {
for (int j = 0; j < 4; j++) {
Instant start = Instant.now();
for (int i = 0; i < 10000; i++) {
// Try various implementations here...
String s = "first";
if (true) {
s += "second";
}
if (true) {
s += "third";
}
if (true) {
s += "fourth";
}
}
System.out.println("Took: " + Duration.between(start, Instant.now()).toMillis() + " millis");
}
}
}
If performance turns out not to be an issue then optimise for the human and make it as readable and maintainable as possible.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.