本问题已经有最佳答案,请猛点这里访问。

我一直在阅读我的团队中其他开发人员生成的代码,他们似乎更喜欢使用+=进行字符串连接,而我更喜欢使用.concat(),因为它更容易阅读。

我正在尝试准备一个论据,为什么使用.concat()更好,我想知道,两者之间的效率有什么不同?

我们应该选择哪个选项?

public class Stuff {
public static void main(String[] args) {
String hello ="hello";
hello +="world";
System.out.println(hello);
String helloConcat ="hello".concat("world");
System.out.println(helloConcat);
}
}

请查看stackoverflow.com/questions/47605/java-string-concatenation

由于String在java中是不可变的,因此当您执行+,+=或concat(String)时,会生成一个新的String。 String越大,所需的时间越长 - 复制的次数越多,产生的垃圾就越多。

今天的java编译器优化了你的字符串连接以使其最佳,例如

System.out.println("x:"+x+" y:"+y);

编译器将其生成为:

System.out.println((new StringBuilder()).append("x:").append(x).append(" y:").append(y).toString());

我的建议是编写更易于维护和阅读的代码。

此链接显示StringBuilder与StringBuffer和String.concat的性能 - 完成正确

没关系。现代Java编译器,JVM和JIT将以这样的方式优化您的代码,使差异可能很小。您应该努力编写更易读,更易于维护的代码。

对于移动处理器或资源较低的情况,你会怎么说呢,这些最小的无关紧要?

@Pratik:那些是优化确实重要的情况。 OPs的问题并未说明需要进行微观优化。当然,你必须要小心根据你的环境做什么。如果你想编写一个操作系统,如果你想要它非常快速的话,你就不能用慢动态语言来编写它。

我不确定你在想什么优化。

@Tom:首先看看@aioobes的回答。这不是整个故事,因为JIT可以在运行时更优化此代码。准确的优化是什么?这需要在JVM和JIT的引擎盖下偷看,所以如果你愿意,你可以这样做。根据我的理解,在过去的15年里,它们都经过了大量优化,所以他们可能会做很多技巧来加速一切。

@aioobes的答案实际上表明,看起来非常相似的源代码实际上会生成完全不同的目标代码 - 这是反对你所说的内容的论据。真的,没有太多小字节码 - >机器码优化可以用这样不同的代码。

我同意@darioo和其他大多数答案。始终首先考虑可读性(和可维护性)。 (对于像这样的简单情况,现代JIT编译器应该没有麻烦。)

但是,这是与您的程序对应的字节码。 (注意+=方法导致StringBuilder,这通常是构造字符串时的首选方法。)

// String hello ="hello";
0: ldc #2; //String hello
2: astore_1
// hello +="world";
3: new #3; //class java/lang/StringBuilder
6: dup
7: invokespecial #4; //Method StringBuilder.""
10: aload_1
11: invokevirtual #5; //Method StringBuilder.append
14: ldc #6; //String world
16: invokevirtual #5; //Method StringBuilder.append
19: invokevirtual #7; //Method StringBuilder.toString
// System.out.println(hello);
22: astore_1
23: getstatic #8; //Field System.out
26: aload_1
27: invokevirtual #9; //Method PrintStream.println
// String helloConcat ="hello".concat("world");
30: ldc #2; //String hello
32: ldc #6; //String world
34: invokevirtual #10; //Method String.concat
37: astore_2
// System.out.println(helloConcat);
38: getstatic #8; //Field System.out
41: aload_2
42: invokevirtual #9; //Method PrintStream.println
45: return

在可读性方面,我认为你错了。 +胜过.concat()。如果您使用的是+=,则可能需要考虑StringBuilder.append为循环保持相同的StringBuilder。

在性能方面,concat优于+。只要你只使用一个或两个。

在concat的情况下,您将最终创建一个String对象,其大小正确char[]。它就像你能得到的那样最佳。

对于+,javac生成构造StringBuilder以执行追加然后转换为String的代码。从1.5你创建:

A StringBuilder(废物)

StringBuilder的初始char[](废物)

如果结果序列太长,则第二个更大的char[](废物)

结果String。

String的char[]。

但是,您很少看到concat,因为它更难以阅读。与其他情况相比,表现几乎可以肯定是海洋中的下降(提示:在优化之前尝试信封背面)。

Concat绝对是两个字符串连接的更快选择,我不知道为什么javac内部使用

(new StringBuilder(String.valueOf(s1))).append(s2).toString()

代替

s1.concat(s2)

对于s1 + = s2。查看我对类似问题的回答连接运算符(+)vs concat()

你应该做你发现的最短,最清楚的事情。

但是,为了你的兴趣。

String hello ="hello" +"world";

最快的是编译将两个String合并为一个。

对于两个字符串来说这是最快的,因为它避免了创建StringBuilder。

String helloConcat ="hello".concat(world);

但是,如果您有两个以上的字符串使用StringBuilder,则隐式或显式最快。

总之,我会使用+除非你在一个循环中使用它,在这种情况下我可能会明确地使用StringBuilder来提高性能。

我发现这个艺术并做了这个测试:

public static void main(String[] args) {
String s1 = generateString();
String s2 = generateString();
String s3 = generateString();
String s4 = generateString();
String s5 = generateString();
String s6 = generateString();
long e = System.currentTimeMillis();
for(int i=0;i<10000000;i++){
//StringBuilder > concat> plus >StringBuffer >plusEqual(">"means faster than)
//concatPlus(s1 , s2 , s3 , s4 , s5 , s6);//4204ms
//concatBuilder(s1 , s2 , s3 , s4 , s5 , s6);//2562ms
//concatBuffer(s1 , s2 , s3 , s4 , s5 , s6);//4610ms
//concatPlusEqual(s1 , s2 , s3 , s4 , s5 , s6);//9843ms
//concatConcat(s1 , s2 , s3 , s4 , s5 , s6);//3036ms
}
System.out.println(System.currentTimeMillis()-e);
}
public static String concatPlusEqual(String s1, String s2, String s3, String s4,
String s5, String s6) {
String result ="";
result += s1;
result += s2;
result += s3;
result += s4;
result += s5;
result += s6;
return result;
}
public static String concatConcat(String s1, String s2, String s3, String s4,
String s5, String s6) {
String result = new String();
result.concat(s1);
result.concat(s2);
result.concat(s3);
result.concat(s4);
result.concat(s5);
result.concat(s6);
return result;
}
public static String concatBuffer(String s1, String s2, String s3, String s4,
String s5, String s6) {
return new StringBuffer(s1.length() + s2.length() + s3.length()
+ s4.length() + s5.length() + s6.length()).append(s1)
.append(s2).append(s3).append(s4).append(s5).append(s6)
.toString();
}
public static String concatBuilder(String s1, String s2, String s3, String s4,
String s5, String s6) {
return new StringBuilder(s1.length() + s2.length() + s3.length()
+ s4.length() + s5.length() + s6.length()).append(s1)
.append(s2).append(s3).append(s4).append(s5).append(s6)
.toString();
}
public static String concatPlus(String s1,String s2,String s3,String s4,String s5,String s6) {
return s1 + s2 + s3 + s4 + s5 + s6;
}
public static String generateString()
{
Random rng = new Random();
int length = 10;
String characters ="ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char[] text = new char[length];
for (int i = 0; i < length; i++)
{
text[i] = characters.charAt(rng.nextInt(characters.length()));
}
return new String(text);
}
看起来StringBuilder最快,+=最慢。

仅供参考!