使用+来连接字符串总是一个坏主意

我的代码如下:

String s = ""; for (My my : myList) { s += my.getX(); } 

当我这样做时,Findbugs总是会报错。

如果你手动连接我会用+

 String word = "Hello"; word += " World!"; 

但是,如果你是迭代和连接我会建议StringBuilder

 StringBuilder sb = new StringBuilder(); for (My my : myList) { sb.append(my.getX()); } 

String对象在Java中是不可变的。 每个+表示另一个对象。 您可以使用StringBuffer来最小化创建的对象的数量。

每次执行string+=string ,都会调用这样的方法:

 private String(String s1, String s2) { if (s1 == null) { s1 = "null"; } if (s2 == null) { s2 = "null"; } count = s1.count + s2.count; value = new char[count]; offset = 0; System.arraycopy(s1.value, s1.offset, value, 0, s1.count); System.arraycopy(s2.value, s2.offset, value, s1.count, s2.count); } 

在StringBuilder的情况下,它涉及:

 final void append0(String string) { if (string == null) { appendNull(); return; } int adding = string.length(); int newSize = count + adding; if (newSize > value.length) { enlargeBuffer(newSize); } string.getChars(0, adding, value, count); count = newSize; } 

你可以清楚地得出结论, string + string会产生很多开销,我认为如果可能的话应该避免。 如果您认为使用StringBuilder很笨或很长,您可以创建一个方法并间接使用它,例如:

 public static String scat(String... vargs) { StringBuilder sb = new StringBuilder(); for (String str : vargs) sb.append(str); return sb.toString(); } 

并使用它像:

 String abcd = scat("a","b","c","d"); 

在C#中,我告诉它与string.Concat(); 。 在你的情况下,为scat编写重载是明智的,例如:

 public static String scat(Collection vargs) { StringBuilder sb = new StringBuilder(); for (Object str : vargs) sb.append(str); return sb.toString(); } 

然后你可以用:

 result = scat(myList) 

编译器可以优化一些东西,比如

“富” +“酒吧”

StringBuilder s1 = new StringBuilder(); 。s1.append( “foo” 的)附加( “条”);

然而,这仍然不是最理想的,因为它以默认大小16开始。尽管你应该找到最大的瓶颈,然后沿着列表工作。 尽管如此,特别是如果你能够计算出最佳的初始化大小,那么在使用SB模式的习惯中并没有什么坏处。

过早优化可能很糟糕,并且通常会降低可读性,通常是完全没必要的。 如果它更具可读性,请使用+ ,除非您确实有一个最重要的问题。

使用“+”并不总是“坏”。 在任何地方使用StringBuffer都会使代码变得非常笨重。

如果有人在密集的,时间关键的循环中放了很多“+”,我会生气。 如果有人在很少使用的代码中放了很多“+”,我就不在乎了。

我会说在下面使用plus:

String c = "a" + "b"

并在其他地方使用StringBuilder类。 正如在第一种情况中已经提到的,它将由编译器进行优化,并且它更具可读性。

FindBugs应该争论使用连接运算符(无论是“+”还是“+ =”)的原因之一是可本地化。 在您给出的示例中并不是那么明显,但在以下代码的情况下,它是:

 String result = "Scanning found " + Integer.toString(numberOfViruses) + " viruses"; 

如果这看起来有点熟悉,则需要更改编码风格。 问题是,它在英语中听起来很棒,但对翻译来说可能是一场噩梦。 这只是因为你不能保证翻译后句子的顺序仍然是相同的 – 有些语言将翻译为“1 blah blah”,有些语言将翻译成“等等等等”。 在这种情况下,您应该始终使用MessageFormat.format()来构建复合句子,并且使用连接运算符显然是国际化错误。

BTW。 我在这里放了另一个i18n缺陷,你能发现它吗?

两个字符串串联的运行时间与字符串的长度成正比。 如果它在循环中使用,则运行时间总是在增加。 因此,如果在循环中需要连接,那么最好使用像Anthony建议的StringBuilder