再次对弦追加vs concat vs +

时间:2012-01-22 16:13:38

标签: java string performance coding-style

可能是我分裂头发,但我想知道以下情况:

String newString = a + b + c;  //case 1


String newString = a.concat(b).concat(c);   //case 2

StringBuilder newString = new StringBuilder(); //case 3
newString.append(a);
newString.append(b);    
newString.append(c);

哪个最好用?

我的意思是任何方式

阅读这些内容,其他帖子说案例3不是最佳表现,其他案例1案例3最终会出现在案例3等中。

更具体一点。

例如,将所有内容放在一边,如果你必须维护他的代码,哪种风格更适合从另一个程序员那里看到它?

或者您认为哪种编程效率更高? 或者你会认为更快等等。

我不知道如何表达这一点。

答案如:案例3可以更快,但绝大多数程序员更喜欢案例1,因为如果它在某种程度上得到了详细阐述,它也是最可读的

6 个答案:

答案 0 :(得分:22)

案例1简洁明了,表达了意图,相当于案例3.

案例2的效率较低,而且可读性较差。

案例3几乎与案例1一样有效,但更长,更不易读。

使用案例3只有在必须在循环中连接时才能使用。否则,编译器将情况1编译为情况3(除了它使用new StringBuilder(a)构造StringBuilder),这使得它比你的情况3)更有效。

答案 1 :(得分:7)

案例3是性能最高的形式,但JVM将案例1转换为案例3。

但我认为案例2是最差的,它不像案例1那样可读,而不像案例3那样。

如果你想在一个循环中连接字符串只是用例3,你可以很容易地测试性能增益,但是如果它不在一个循环中(或者你没有在一个序列中附加大量字符串)它们几乎是相同。

您不应使用+运算符的情况为:

String a = "";
for (String x : theStrings) {
    a += x;
}

String a = b + c;
a = a + d;
a = a + e;
a = a + f;

答案 2 :(得分:2)

案例3在大多数方面都更好。在案例3中,您不会最终创建3个字符串对象。由于字符串不变性,2将为每个+(或)concat创建字符串对象的开销。

编辑:重新阅读文件并同意大多数评论,案例1是案例3。

答案 3 :(得分:1)

对于简单的情况,使用+显然更具可读性。

对于罕见的更复杂的案例,StringBuilder是有道理的。如果您要跨行分割,那么+很快就会成为性能阻力。循环从O(n)性能变为O(n ^ 2) - 如果 n 很小则不成问题,但如果 n 在尴尬的情况下可能很大则是一个大问题(可能是在做一些关键的事情,或者某人是恶意的时候)。

与其他答案相反,如果您只有三个字符串,则concat可能是性能优胜者。我是精神病吗?不。考虑其他两个选项。您正在创建一个带有数组的StringBuilder对象。附加字符串可能需要更换数组,并且您可能在数组的末尾留下奇数位(这是分配的特定粒度,因此一些额外的char可能会或可能不会增加内存使用量) 。如果您讨厌读取代码的每个人,您可以计算必要的容量。最好的情况,两个数组(一个用于StringBuilder,一个用于String(过去八年没有共享))每个结果文本的大小和另外两个对象(StringBuilderString)。现在,对于concat,您将分配给具有两个数组的String个对象,但第一个数组将更短c.length()。这是一场胜利!好吧,不是为了可读性。

免责声明:JVM可以进行疯狂优化,包括转义分析后的堆栈分配和核心类的特殊大小写。与手工混淆的代码相比,它们更有可能优化常见和简单的代码。

答案 4 :(得分:0)

在使用JDK 1.8进行性能分析时,我发现案例2是性能方面的赢家。

class Solution {
public static void main(String[] args) {
   String s ="ABC", s1 = "", s2 = "", s3 = "";
   long t1 = System.nanoTime();
   for(int i = 1; i < 11; i++) {
       s1 = s1 + s;
   }
   System.out.println(System.nanoTime() - t1);
   System.out.println(s1);

   long t2 = System.nanoTime();
   for(int i = 1; i < 11; i++) {
       s2 = s2.concat(s);
   }
   System.out.println(System.nanoTime() - t2);
   System.out.println(s2);

   long t3 = System.nanoTime();
   StringBuilder sb = new StringBuilder();
   for(int i = 1; i < 11; i++) {
       sb.append(s);
   }
   s3 = sb.toString();
   System.out.println(System.nanoTime() - t3);
   System.out.println(s3);
 }
}

结果:

40615

ABCABCABCABCABCABCABCABCABCABC

9157

ABCABCABCABCABCABCABCABCABCABC

20243

ABCABCABCABCABCABCABCABCABCABC

答案 5 :(得分:0)

除上述内容外,在JEP 280下仅针对字符串连接 进行了显着的性能改进。

请参阅 https://openjdk.java.net/jeps/280 和解释 https://dzone.com/articles/jdk-9jep-280-string-concatenations-will-never-be-t

简而言之,这意味着从Java 9 "Hello " + "world"字符串连接是甚至考虑性能的首选方式。