对于字符串连接,我们可以使用concat()
或concat运算符(+)
。
我尝试了以下性能测试,发现concat()
更快,并且是一种内存有效的字符串连接方式。
字符串连接比较100,000次:
String str = null;
//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for(int i=0; i<100000; i++){
str = "Hi";
str = str+" Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();
long timetaken1 = time2-time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator :" + "Time taken =" + timetaken1 +
" Memory Consumed =" + memoryTaken1);
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for(int j=0; j<100000; j++){
str = "Hi";
str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4-time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method :" + "Time taken =" + timetaken2 +
" Memory Consumed =" + memoryTaken2);
结果
Concat operator: Time taken = 31; Memory Consumed = 2259096
Concat method : Time taken = 16; Memory Consumed = 299592
如果concat()
比运算符更快,那么我们何时应该使用连接运算符(+)
?
答案 0 :(得分:36)
concat方法总是生成一个带有连接结果的新String。
plus运算符由StringBuilder创建支持,附加所需的所有String值,并进一步调用toString()。
因此,如果你需要连接两个值,concat()将是更好的选择。如果需要连接100个值,则应使用加号运算符或显式使用StringBuilder(例如,如果在循环中追加)。
答案 1 :(得分:12)
实际上s1 + s2和s1.concat(s2)非常不同。
s1 + s2由javac转换为
(new StringBuilder(String.valueOf(s1)).append(s2).toString();
如果你反编译.class你可以看到它。这种结构效率不高;它涉及最多三个新的char []分配和三个char []复制操作。
s1.concat(s2)总是一个新的char [] +一个复制操作,参见String.java
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
char buf[] = new char[count + otherLen];
getChars(0, count, buf, 0);
str.getChars(0, otherLen, buf, count);
return new String(0, count + otherLen, buf);
}
请注意,新的String(int,int,char [])是String的包私有构造函数。它直接使用char buf [],没有通常的复制,以确保字符串不变性的buf不可见性。
答案 2 :(得分:7)
您的测试需要运行至少2秒,每个循环在一个单独的方法中才有意义。短期测试可能难以重现和比较。从您的计时看来,您正在使用Windows(即因为您的时间是16和31毫秒;)请尝试使用System.nanoTime()。当你的循环迭代超过10,000次时,整个方法被编译。这意味着您的后一个方法在启动时已经被编译。
在回答你的问题时,在添加两个字符串时,concat会略微加快。但是,它带有打字和概念开销,可能比您节省的CPU大得多。即使你的测试重复100,000次,它也可以节省不到15毫秒的时间,而且它的成本远远超过你的时间(这可能是更值得的)你可以在未来版本的JVM中找到,差异总是得到优化,代码的复杂性仍然存在。
String str = null;
//------------Using Concatenation operator-------------
long time1 = System.currentTimeMillis();
long freeMemory1 = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 10000; i++) {
str = "Hi";
str = str + " Bye";
}
long time2 = System.currentTimeMillis();
long freeMemory2 = Runtime.getRuntime().freeMemory();
long timetaken1 = time2 - time1;
long memoryTaken1 = freeMemory1 - freeMemory2;
System.out.println("Concat operator :" + "Time taken =" + timetaken1 + " Memory Consumed= " + memoryTaken1);
str = null;
//------------Using Concat method-------------
long time3 = System.currentTimeMillis();
long freeMemory3 = Runtime.getRuntime().freeMemory();
for (int j = 0; j < 10000; j++) {
str = "Hi";
str = str.concat(" Bye");
}
long time4 = System.currentTimeMillis();
long freeMemory4 = Runtime.getRuntime().freeMemory();
long timetaken2 = time4 - time3;
long memoryTaken2 = freeMemory3 - freeMemory4;
System.out.println("Concat method :" + "Time taken =" + timetaken2 + " Memory Consumed= " + memoryTaken2);
使用-XX:-UseTLAB -mx1g
运行时打印
Concat operator :Time taken =12 Memory Consumed= 1291456
Concat method :Time taken =7 Memory Consumed= 560000
使内存使用率约为2:1。在原始问题中,每次运行时结果都会有所不同,有时.concat()
似乎会使用更多。
答案 3 :(得分:3)
我相信连接的“风格”会有所作为。
对于concat(),它在内部创建一个新的char数组缓冲区,并根据该char数组返回一个新字符串。
对于+运算符,编译器实际上将其转换为使用StringBuffer / StringBuilder。
因此,如果你连接两个字符串,concat()绝对是一个更好的选择,因为创建的对象数只是结果String(和里面使用的char缓冲区),而使用+
运算符将译成:
result = strA + strB;
-- translate to -->
result = new StringBuilder(strA).append(strB).toString();
创建了一个额外的StringBuilder实例。
但是,如果要连接,例如连续五个字符串,每个concat()将创建一个新的String对象。在使用+
运算符时,编译器会将语句转换为具有多个追加操作的StringBuilder。它肯定会节省大量不必要的临时对象实例:
result = strA + strB + strC + strD + strE;
-- translate to -->
result = new StringBuilder(strA).append(strB).append(strC).append(strD).append(strE).toString();
答案 4 :(得分:0)
如果只使用&gt; = Java 1.5并且不声明你的基本字符串(你想要的话),你可以始终使用+
连接)循环之外。在Java 1.5中,它会导致创建new StringBuilder
并对其进行处理直到字符串完成。这是最快的方式。
无论如何 - 如果你处于循环中(并用+
连接字符串) - 循环的每次迭代都会创建new StringBuilder
- 这不是最好的主意。因此,您应该强制使用StringBuilder
或StringBuffer
(线程安全)类。
通常,此链接会清楚地回答您的问题,并为您提供完整的知识:
http://littletutorials.com/2008/07/16/stringbuffer-vs-stringbuilder-performance-comparison/
答案 5 :(得分:0)
虽然操作员和方法都提供相同的输出,但它们在内部工作的方式不同。
将str1与str2连接并输出字符串的concat()
方法对于少量连接更有效。
但是使用连接运算符'+',str1+=str2
;将被解释为
str1 = new StringBuilder().append(str1).append(str2).toString();
使用较少数量的字符串进行连接时,可以使用concat方法。但是,如果使用大量字符串,StringBuilder方法在性能方面会很快。
答案 6 :(得分:-2)
实际上,两者都是一样的。如果您看到concat(String paramString)
的代码,它将返回一个新的字符串对象,并且在(+)运算符中它还将生成一个新的字符串对象。
如果您不想创建新对象,请使用字符串构建器连接两个字符串。
答案 7 :(得分:-2)
通常,将字符串与+
和concat()
连接起来是一种不好的做法。如果要创建字符串,请改用StringBuilder
。