提高Java中字符串连接的性能

提高Java中字符串连接的性能,java,performance,Java,Performance,可能重复: 如何提高这段代码的性能: public static String concatStrings(Vector strings) { String returnValue = ""; Iterator iter = strings.iterator(); while( iter.hasNext() ) { returnValue += (String)iter.next(); } return returnValue; }

可能重复:

如何提高这段代码的性能:

public static String concatStrings(Vector strings) {
    String returnValue = "";

    Iterator iter = strings.iterator();
    while( iter.hasNext() ) {
        returnValue += (String)iter.next();
    }

    return returnValue;
}

您可以考虑使用,而不是对单个字符串执行+=操作。字符串在Java中是不可变的,这意味着一旦创建字符串对象,就不能修改它。在循环中的字符串上使用+=将导致创建许多单独的字符串实例,这可能会产生性能问题。StringBuilder可以连接字符串,而无需创建新实例,这可能会节省一些时间,具体取决于具体的场景。

此外,如果希望加快速度,可以重构代码以使用ArrayList而不是Vector。ArrayList不是线程安全的,因此它比Vector稍快一点(取决于具体情况,可能相差0%,也可能相差5%)

每次调用+=。比如说

String theString = "1"; //Makes an immutable String object "1"
theString +="2"; //Makes a new immutable String object "12"
theString +="3"; //makes a new immutable String object "123"
使用字符串生成器可以避免此问题

StringBuilder sb = new StringBuilder("1"); //Makes a StringBuilder object holding 1
sb.append("2"); //The same StringBuilder object now has "12" in it.
sb.append("3"); //The same StringBuidler object now has "123" in it. 
String theString = sb.toString(); //Creates a new String object with "123" in it 

请注意,在第一个示例中,我们创建了所有这些中间字符串,而在第二个示例中,我们只创建了StringBuilder和最终字符串(在这两个示例中,当我们将它们用作参数时,我们都创建了“1”、“2”和“3”)。您可以看到,在第一个示例中创建的对象较少,如果您在字符串中添加了大量内容,您可以想象这样做的效果

正如其他答案所建议的,使用a可能是更好的选择

问题中给出的代码实际上将(使用Sun的
javac
)编译成以下代码:

public static String concatStrings(Vector strings) {
    String returnValue = "";

    Iterator iter = strings.iterator();
    while( iter.hasNext() ) {
        String str = (String)iter.next();

        StringBuilder sb = new StringBuilder(returnValue);
        sb.append(str);

        returnValue = sb.toString();
    }

    return returnValue;
}
编译器将把
+=
字符串连接更改为使用
StringBuilder
的字符串连接。但是,编译器可能会重写循环中的代码,因此每次迭代都会创建一个新的
StringBuilder
实例,这对性能不是很友好

因此,在这种情况下,最好自己在循环外部创建一个
StringBuilder
,并执行手动字符串连接:

public static String concatStrings(Vector strings) {
    StringBuidler returnValueBuilder;

    Iterator iter = strings.iterator();
    while( iter.hasNext() ) {
        returnValueBuilder.append((String)iter.next());
    }

    return returnValueBuilder.toString();
}

除了使用StringBuilder外,您还可以预先浏览字符串列表,并计算StringBuilder所需的字符串的确切大小。然后将该值传递给StringBuilder构造函数。请注意,这属于过早优化的范畴,但您确实要求性能。。。(您应该查看用于增加StringBuilder/StringBuffer缓冲区的代码,它具有教育意义)

公共静态字符串concatStrings(列表字符串){
StringBuilder sb=新的StringBuilder();
用于(字符串s:字符串){
某人追加;
}    
使某人返回字符串();
}
一些评论:

  • 每当需要在循环中构建字符串时,请使用
    StringBuilder
    • +
      对于简单的连接很好,但是对于增量构建却很糟糕
  • 只要有可能,请使用以提高可读性
  • 是同步的;如果您不需要这个(昂贵的)功能,只需使用一个
不要使用原始类型
  • 只允许使用原始类型作为对遗留代码兼容性的让步。强烈反对在Java编程语言中引入泛型之后编写的代码中使用原始类型。Java编程语言的未来版本可能会禁止使用原始类型

  • 有效Java第二版:第23项:不要在新代码中使用原始类型

    如果使用原始类型,则会失去泛型的所有安全性和表达性优势

另见
私有静态最终整数平均字符串长度=10;//使用10是任意的
公共静态最终字符串concatStrings(最终集合字符串){
if(strings==null)返回null;
final int size=strings.size();
如果(size==0)返回“”;
if(size==1)返回strings.get(0);
最终StringBuilder返回值=
新StringBuilder(平均字符串长度*大小);
用于(字符串s:字符串){
returnValue.append;
}
返回returnValue.toString();
}
也许有点过火了,下面是我能想到的
concatStrings()
每一个优化方法-上面演示了-其中一些可能不适用于您的环境:

  • 使用-对于这些连续的连接,它的效率要高得多
  • 用于指定可能需要的容量,如果有任何方法可以预测(使用上述平均大小,但其他方法可能更方便)
  • 使用参数类型可以实现比同步更高效的数据结构,而且调用者具有更大的灵活性(例如,不需要将
    集合
    复制到
    向量
    就可以调用此方法)
  • 硬编码简单案例,如果可能(例如上面的
    null
    、size
    0
    和size
    1
    案例)
  • 用于促进JIT内联和优化
  • 缓存
    字符串的大小(如果多次使用)。(例如,在上述代码中使用了3次。)
最后,如果经常对大量字符串执行此操作,请查看

  • Java文章的绳索-
  • Java实现的诀窍-
  • 绳索(维基百科)-

除了使用ARARYLIST和StringBuilder之外,让我们考虑一下。 在现代计算机科学范式中,空间几乎总是可以用来交换时间的(也许,这是一种主观陈述)。对于给定的场景,使用下面的代码,将使用额外的O(N)空间,其中N=没有字符串(用于保存list.toArray()的新缓冲区)。这至少比使用迭代器要好(打开AbstractList.Iterator()。重要的是,通过在一次迭代中同时计算两个字符串的串联,时间复杂度显著提高,从而重新计算

public static String concatStrings(List<String> strings) {
    StringBuilder sb = new StringBuilder();
    for (String s : strings) {
       sb.append(s);
    }    
    return sb.toString();
}
private static final int AVERAGE_STRING_LENGTH = 10;  // Using 10 is arbitrary

public static final String concatStrings(final Collection<String> strings) {
    if (strings == null)   return null;

    final int size = strings.size();
    if (size == 0)         return "";
    if (size == 1)         return strings.get(0);

    final StringBuilder returnValue =
        new StringBuilder(AVERAGE_STRING_LENGTH * size);

    for (String s : strings) {
        returnValue.append(s);
    }

    return returnValue.toString();
}
    StringBuilder sb = new StringBuilder();
    Object[] o = list.toArray();
    //For even no of Strings
    if(o.length % 2 == 0){
        concatFaster(sb, o);
    } else {
        //For odd no of Strings
        concatFaster(sb, o);
        sb.append(o[o.length-1]); // For the odd index
    }

    public static void concatFaster(StringBuilder sb, Object[] o) {
    for (int i = 0; i < o.length - 1; i+=2) {
        sb.append(o[i]).append(o[i+1]);
    }
}