为啥“.concat(String)”比“+”快这么多? [复制]
Posted
技术标签:
【中文标题】为啥“.concat(String)”比“+”快这么多? [复制]【英文标题】:Why is ".concat(String)" so much faster than "+"? [duplicate]为什么“.concat(String)”比“+”快这么多? [复制] 【发布时间】:2014-04-11 22:40:09 【问题描述】:我编写的一些代码比较了将字符串与"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 纳秒
String str2 = str.concat(str)
: 52.36809985 纳秒
.concat
比+
快 66.20539483 纳秒
这表明即使使用循环和分配给新字符串,.concat
也比 +
快两倍以上。当我使用更长的字符串 (str == "this is a really really very long string that is very long"
) 时,它会快大约三倍。这特别奇怪,因为如果.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");
【问题讨论】:
@SotiriosDelimanolis 那是在问+=
是否与.concat
相同,我在问为什么.concat
比+
快。
但是这个answers你的question
我猜应该是关闭了,根据这个:meta.stackexchange.com/questions/192508/…
好的。根据this,它应该不是重复的。
另一种选择是关闭它,因为它基于有缺陷的基准。
【参考方案1】:
编辑:回顾这个答案,我现在意识到它是多么不科学和投机。虽然不一定是错的,但我不再相信它的正确性。
这里是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"
编译为new StringBuilder().append("string").append("string").toString()
。1append
的源代码使用它的超类'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, 0, buf, 0, Math.min(value.length, len + otherLen));
System.arraycopy(str.value, 0, buf, len, 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, 0, value, 0, (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, 0, value, value.length, len - 0);
count += len;
return this;
删除永远不会使用给定字符串执行的代码,并删除它们之间相同的代码后:
//////////////concat
int len = value.length;
len + otherLen
System.arraycopy(value, 0, buf, 0, Math.min(value.length, len + otherLen));
System.arraycopy(str.value, 0, buf, len, 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, 0, value, 0, (value.length <= newCapacity) ? value.length : newCapacity);
if(0 < 0)
if(len > str.value.length)
if(0 > len)
System.arraycopy(str.value, 0, value, value.length, 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
您可以看到 one concat 在几乎所有情况下都会比 one append 快,并且+
编译为 two append 和toString
。
1:A: String concatenation: concat() vs + operator
【讨论】:
以上是关于为啥“.concat(String)”比“+”快这么多? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
为啥 std::string_view 比 const char* 快?
为啥在片段中从 char* 转换为 std::string 比转换为 const char* 更可取?
为啥 Swift String.Index 保持其索引值比真实值大 4 倍?