使用+来连接字符串总是一个坏主意
我的代码如下:
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
。