java – 为什么“.concat(String)”比“”快得多?

参见英文答案 > String concatenation: concat() vs “+” operator11
我做的一些代码比较了将字符串连接到“string”“string”所花费的时间:
for(int i = 0; i < 100000000L; i++)
{
    String str2 = str + str;
}

到“string”.concat(“string”):

for(int i = 0; i < 100000000L; i++)
{
    String str2 = str.concat(str);
}

其中str ==“string”.

我得到的输出与此一致,尽管平均差异通常更接近于61纳秒:

String str2 = str + str: 118.57349468 nanoseconds

String str2 = str.concat(str): 52.36809985 nanoseconds

.concat is faster than + by 66.20539483 nanoseconds

这表明即使循环和赋值到一个新的字符串,.concat比二分之二更快.当我使用一个更长的字符串(str ==“这是非常长的真正非常长的字符串”),它的速度比三分之一快.这是特别奇怪的,因为如果.concat更快,不应该编译成.concat?

我的主要问题是:为什么.concat更快?

完整的代码,以防您想要运行它并进行实验:

public class TimeCompare
{
    public static void main(String[] args)
    {
        final long times = 100000000L;

        String str = "String";

        long start1 = System.nanoTime();

        for(int i = 0; i < times; i++)
        {
            String str2 = str + str;
        }

        long end1 = System.nanoTime();
        long time1 = end1 - start1;

        System.out.println((double)(time1) / times);
        System.out.println();

        long start2 = System.nanoTime();

        for(int i = 0; i < times; i++)
        {
            String str2 = str.concat(str);
        }

        long end2 = System.nanoTime();
        long time2 = end2 - start2;

        System.out.println((double)(time2) / times);
        System.out.println();

        System.out.println(".concat is faster than \"+\" by " + ((double)(time1 - time2) / times) + " nanoseconds");
    }
}

解决方法

以下是concat的源代码
public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    int len = value.length;
    char buf[] = Arrays.copyOf(value,len + otherLen);
    str.getChars(buf,len);
    return new String(buf,true);
}

“string”“string”编译为新的StringBuilder().append(“string”).append(“string”).toString().1 append的源代码使用其超类’,AbstractStringBuilder,

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0,len,value,count);
    count += len;
    return this;
}

方法的源代替方法调用后:

/////////////////concat

int otherLen = str.length();
if (otherLen == 0) {
    return this;
}

int len = value.length;

char buf[] = ((Object)value.getClass() == (Object)Object[].class)
    ? (T[]) new Object[len + otherLen]
    : (T[]) Array.newInstance(value.getClass().getComponentType(),len + otherLen);

System.arraycopy(value,buf,Math.min(value.length,len + otherLen));

System.arraycopy(str.value,str.value.length);

return new String(buf,true);

///////////////append

if (str == null) str = "null";
int len = str.length();

if (value.length + len - value.length > 0)
{
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - value.length + len < 0)
        newCapacity = value.length + len;
    if (newCapacity < 0) {
        if (value.length + len < 0) // overflow
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }

    value = ((Object)value.getClass() == (Object)Object[].class)
        ? (T[]) new Object[newCapacity]
        : (T[]) Array.newInstance(value.getClass().getComponentType(),newCapacity);

    System.arraycopy(value,(value.length <= newCapacity) ? value.length : newCapacity;
}

if (0 < 0) {
    throw new Stringindexoutofboundsexception(0);
}
if (len > str.value.length) {
    throw new Stringindexoutofboundsexception(len);
}
if (0 > len) {
    throw new Stringindexoutofboundsexception(len - 0);
}
System.arraycopy(str.value,value.length,len - 0);

count += len;
return this;

删除不会使用给定字符串执行的代码,并删除它们之间相同的代码

//////////////concat

int len = value.length;
len + otherLen
System.arraycopy(value,len + otherLen));
System.arraycopy(str.value,str.value.length);
this.value = value;

/////////////////append

if(value.length + len - value.length > 0)
int newCapacity = value.length * 2 + 2;
if(newCapacity - value.length + len < 0)
if(newCapacity < 0)
System.arraycopy(value,(value.length <= newCapacity) ? value.length : newCapacity);
if(0 < 0)
if(len > str.value.length)
if(0 > len)
System.arraycopy(str.value,len - 0);
count += len;

在计算所有操作和删除concat和append之间相同的操作之后:

concat
--------
int assignment: 0
int +/-: 0
int comparison: 0
char[] assignment: 1
arraycopy: 0
int *: 0


append
--------
int assignment: 1
int +/-: 5
int comparison: 6
char[] assignment: 0
arraycopy: 0
int *: 1

您可以看到,在几乎所有情况下,一个concat都将比一个附加更快,并编译为两个追加和一个toString.

[1]:A: String concatenation: concat() vs + operator

相关文章

最近看了一下学习资料,感觉进制转换其实还是挺有意思的,尤...
/*HashSet 基本操作 * --set:元素是无序的,存入和取出顺序不...
/*list 基本操作 * * List a=new List(); * 增 * a.add(inde...
/* * 内部类 * */ 1 class OutClass{ 2 //定义外部类的成员变...
集合的操作Iterator、Collection、Set和HashSet关系Iterator...
接口中常量的修饰关键字:public,static,final(常量)函数...