这取决于字符串的大小。
请看下面的示例:
static final int MAX_ITERATIONS = 50000;
static final int CALC_AVG_EVERY = 10000;
public static void main(String[] args) {
printBytecodeVersion();
printJavaVersion();
case1();
case2();
case3();
}
static void case1() {
System.out.println("[str1.concat(str2)]");
List<Long> savedTimes = new ArrayList();
long startTimeAll = System.currentTimeMillis();
String str = "";
for (int i = 0; i < MAX_ITERATIONS; i++) {
long startTime = System.currentTimeMillis();
str = str.concat(UUID.randomUUID() + "---");
saveTime(savedTimes, startTime);
}
System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}
static void case2() {
System.out.println("[str1+=str2]");
List<Long> savedTimes = new ArrayList();
long startTimeAll = System.currentTimeMillis();
String str = "";
for (int i = 0; i < MAX_ITERATIONS; i++) {
long startTime = System.currentTimeMillis();
str += UUID.randomUUID() + "---";
saveTime(savedTimes, startTime);
}
System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}
static void case3() {
System.out.println("[str1.append(str2)]");
List<Long> savedTimes = new ArrayList();
long startTimeAll = System.currentTimeMillis();
StringBuilder str = new StringBuilder("");
for (int i = 0; i < MAX_ITERATIONS; i++) {
long startTime = System.currentTimeMillis();
str.append(UUID.randomUUID() + "---");
saveTime(savedTimes, startTime);
}
System.out.println("Created string of length:" + str.length() + " in " + (System.currentTimeMillis() - startTimeAll) + " ms");
}
static void saveTime(List<Long> executionTimes, long startTime) {
executionTimes.add(System.currentTimeMillis() - startTime);
if (executionTimes.size() % CALC_AVG_EVERY == 0) {
out.println("average time for " + executionTimes.size() + " concatenations: "
+ NumberFormat.getInstance().format(executionTimes.stream().mapToLong(Long::longValue).average().orElseGet(() -> 0))
+ " ms avg");
executionTimes.clear();
}
}
输出:
java字节码版本:8
java.version: 1.8.0_144
[str1.concat(str2)]
10000次连接的平均时间:0.096毫秒
10000次连接的平均时间:0.185毫秒
10000次连接的平均时间:0.327毫秒
10000次连接的平均时间:0.501毫秒
10000次连接的平均时间:0.656毫秒
创建长度为1950000的字符串,用时:17745毫秒
[str1+=str2]
10000次连接的平均时间:0.21毫秒
10000次连接的平均时间:0.652毫秒
10000次连接的平均时间:1.129毫秒
10000次连接的平均时间:1.727毫秒
10000次连接的平均时间:2.302毫秒
创建长度为1950000的字符串,用时:60279毫秒
[str1.append(str2)]
10000次连接的平均时间:0.002毫秒
10000次连接的平均时间:0.002毫秒
10000次连接的平均时间:0.002毫秒
10000次连接的平均时间:0.002毫秒
10000次连接的平均时间:0.002毫秒
创建长度为1950000的字符串,用时:100毫秒
随着字符串长度的增加,
+=
和
.concat
的连接时间也会增加,后者更有效率但仍然不是常数级别。这就是为什么一定需要使用
StringBuilder
的原因。
附注:我认为
何时在Java中使用StringBuilder 并不是这个问题的重复。这个问题讨论了
toString()
,它大多数情况下不会对巨大的字符串进行连接。
2019更新
自从java8
时代以来,情况有所改变。现在(java13),+=
的连接时间似乎与str.concat()
几乎相同。然而,StringBuilder
的连接时间仍然是恒定的。(上面的原始帖子已稍作编辑,以添加更详细的输出)
java字节码版本:13
java版本:13.0.1
[str1.concat(str2)]
10000次字符串连接的平均时间:0.047毫秒平均值
10000次字符串连接的平均时间:0.1毫秒平均值
10000次字符串连接的平均时间:0.17毫秒平均值
10000次字符串连接的平均时间:0.255毫秒平均值
10000次字符串连接的平均时间:0.336毫秒平均值
创建长度为1950000的字符串:
9147毫秒
[str1+=str2]
10000次字符串连接的平均时间:0.037毫秒平均值
10000次字符串连接的平均时间:0.097毫秒平均值
10000次字符串连接的平均时间:0.249毫秒平均值
10000次字符串连接的平均时间:0.298毫秒平均值
10000次字符串连接的平均时间:0.326毫秒平均值
创建长度为1950000的字符串:
10191毫秒
[str1.append(str2)]
10000次字符串连接的平均时间:0.001毫秒平均值
10000次字符串连接的平均时间:0.001毫秒平均值
10000次字符串连接的平均时间:0.001毫秒平均值
10000次字符串连接的平均时间:0.001毫秒平均值
10000次字符串连接的平均时间:0.001毫秒平均值
创建长度为1950000的字符串:
43毫秒
值得注意的是,
bytecode:8/java.version:13
的组合相较于
bytecode:8/java.version:8
有很好的性能优势。
StringBuilder
预先分配多少空间,否则当它用完空间时,会不得不通过创建新的char[]
数组并复制数据来将大小加倍,这是代价高昂的。你可以通过指定大小来欺骗StringBuilder
,这样就不需要创建新的数组——所以如果你认为你的字符串长度约为100个字符,那么你可以将StringBuilder
设置为该大小,它就不必内部扩展了。 - non sequitor