Java 使用+总是一个坏主意吗;串接字符串

Java 使用+总是一个坏主意吗;串接字符串,java,string,internationalization,coding-style,Java,String,Internationalization,Coding Style,我的代码如下: String s = ""; for (My my : myList) { s += my.getX(); } 当我这样做时,Findbugs总是报告错误。字符串对象在Java中是不可变的。每个+表示另一个对象。您可以使用StringBuffer来最小化创建对象的数量。如果您手动连接 String word = "Hello"; word += " World!"; 但是,如果您正在迭代和连接,我建议 编译器可以优化某些东西,例如 “foo”+“bar” 到 Stri

我的代码如下:

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

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

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

如果您手动连接

String word = "Hello";
word += " World!";
但是,如果您正在迭代和连接,我建议


编译器可以优化某些东西,例如

“foo”+“bar”

StringBuilder s1=新的StringBuilder(); s1.附加(“foo”)。附加(“bar”)


但是,这仍然是次优的,因为它以默认大小16开始。就像很多事情一样,你应该找到你最大的瓶颈,然后沿着清单往下走。从一开始就习惯于使用SB模式并没有什么坏处,尤其是当你能够计算出一个最佳的初始化大小时。

过早的优化可能是不好的,因为它通常会降低可读性,并且通常是完全不必要的。如果它可读性更好,请使用
+
,除非您确实有压倒一切的顾虑。

使用“+”并不“总是坏事”。到处使用StringBuffer会使代码变得非常庞大


如果有人把大量的“+”放在一个密集的、时间关键的循环中,我会很恼火。如果有人在一段很少使用的代码中加了很多“+”,我不会在意。

我会在下面说使用plus:

String c=“a”+“b”

并在其他地方使用StringBuilder类。
如前所述,编译器将对其进行优化,使其更具可读性。

每次执行
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();
}

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

String result = "Scanning found " + Integer.toString(numberOfViruses) + " viruses";
如果这看起来有些熟悉,则需要更改编码样式。问题是,它在英语中听起来很棒,但对译者来说可能是一场噩梦。那只是因为你不能保证翻译后句子的顺序仍然是一样的——有些语言会被翻译成“1诸如此类”,有些语言会被翻译成“诸如此类3诸如此类”。在这种情况下,您应该始终使用MessageFormat.format()来构建复合句,而使用串联运算符显然是一个错误


顺便说一句,我在这里放了另一个i18n缺陷,你能发现它吗?

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

是getX();返回字符串?我不认为“总是”不好。但是更多的时候没有更适合的替代方案。使用+连接肯定不是坏事。然而,当你做这样的循环时,这是不好的。@el_quick:如果
getX()
返回一个字符串,那又有什么关系呢?Java将串联转换为+以使用
StringBuilder
。如果要使用一系列方法调用或类似的方法来循环或构建字符串,则只需自己使用
StringBuilder
。另外,
StringBuffer
具有通常不需要的线程安全开销,因此
StringBuilder
通常是一个更好的选择。+1-通常应该避免循环中的串联。另一点:在某些情况下,如果有串字面值被串联,那么实际上使用+会更好,因为一系列串联的文字将被编译为一个字符串。考虑到它在多行上被拆分的方式,我不确定,但我认为编译器会将其优化为
String word=“Hello World!”
。如果您确信应用程序永远不会本地化,那么可以这样使用串联。如果你打算把它翻译成外语,你会有本地化的缺陷。然而,“+”和“+=”在效率上并不等同;e、 g.
word=a+b+c可能比
word=a快得多;单词+=b;单词+=c。因为a+b+c在幕后使用StringBuffer。实际上,编译器可以将其优化为仅
“foobar”
+1用于查找瓶颈
result = scat(myList)
String result = "Scanning found " + Integer.toString(numberOfViruses) + " viruses";