拼接字符串的三种方法
- 加号
- concat()
- StringBuilder/StringBuffer的append()
程序例子
package leif; public class Test { public static void main(String[] args) { String string1 = "1"; long time = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { string1 = string1 + "1"; } System.out.println("加号所花费的时间:" + (System.currentTimeMillis() - time)); String string2 = "2"; time = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { string2.concat("2"); } System.out.println("cancat方法所花费的时间:" + (System.currentTimeMillis() - time)); StringBuilder stringBuilder = new StringBuilder("3"); time = System.currentTimeMillis(); for (int i = 0; i < 50000; i++) { stringBuilder.append("3"); } System.out.println("append方法所花费的时间:" + (System.currentTimeMillis() - time)); } }
程序输出:
结论
append()最快、concat()次之、加号最慢
- 加号
虽然编译器对字符串的加号做了优化,它会使用StringBuilder的append()进行追加,而它最终通过toString()转换成String字符串,上例中“+”拼接的代码即如下:
str = new StringBuilder(str).append("JTZen9").toString();
它与纯粹地使用StringBuilder的append()是不同的:
- 每趟循环都会创建一个StringBuilder对象
- 每次执行完毕都会调用toString()将其转换为字符串
所以,就耗费了更多的时间。
- concat()
源代码:public String concat(String str) { // 追加的字符串长度为0 int otherLen = str.length(); // 如果追加的字符串长度为0,则返回原字符串本身 if (otherLen == 0) { return this; } // 获取原字符串的字符数组的长度 int len = value.length; // 将原字符串的字符数组放到buf数组中 char buf[] = Arrays.copyOf(value, len + otherLen); // 将追加的字符串转化成字符数组,添加到buf中 str.getChars(buf, len); // 产生一个新的字符串 return new String(buf, true); }
整体是一个数组的拷贝,虽然在内存中的处理都是原子性操作,速度非常快,但是最后的return语句创建一个新String对象,也就是每次concat操作都会创建一个新的String对象,这也是限制concat方法速度的原因。
- append()
源代码:public AbstractStringBuilder append(String str) { // 如果是null值,则把null作为字符串处理 if (str == null) { return appendNull(); } int len = str.length(); // 追加后的字符数组长度是否超过当前值 ensureCapacityInternal(count + len); // 字符串复制到目标数组 str.getChars(0, len, value, count); count += len; return this; } private AbstractStringBuilder appendNull() { int c = count; ensureCapacityInternal(c + 4); final char[] value = this.value; value[c++] = 'n'; value[c++] = 'u'; value[c++] = 'l'; value[c++] = 'l'; count = c; return this; } private void ensureCapacityInternal(int minimumCapacity) { if (minimumCapacity - value.length > 0) { expandCapacity(minimumCapacity); } // 加长,并作数组拷贝 }
整个append()都在做字符数组的加长,拷贝等,这些都是基本的数据处理,整个方法内并没有生成对象,只是最后toString()返回一个对象而已。
题外
String str = "My name is "; str = str + "Leif";
相当于
str = new StringBuilder(str).append(“Leif”).toString();
也就是说,该str = str + “Leif”;语句执行完之后,总共有三个对象。String str = "My name is " + "Leif";
JVM会直接把str作为一个对象,即 “My name is Leif”
使用场景
- 大多数情况,我们使用“+”,符合编码习惯和阅读习惯。
- 当在频繁进行字符串的运算(如拼接、替换、删除等),或者在系统性能临界的时候,我们可以考虑使用concat()或append()。