字符串拼接多种实现方式及性能详解

java中字符串拼接有多种方式。但是为了搞清楚它们之间的区别,我做了以下的实验。


一、使用“+”符号拼接


“+”号拼接是第一时间最能想到的方式。但是它的性能却不如人意,下面是我实验的代码:
public static void a(){
long starTime = new Date().getTime();
String string = new String();
for(int i=0;i<50000;i++){
string = string + i;
}
long endTime = new Date().getTime();
System.out.println("“+”号花费时间:"+(endTime - starTime));
}
这种方式花费的时间在6800毫秒左右。(由于机器性能不同,执行的时间也会有所差异。为了保证实验结果的正确性,请都在同一台机器上运行。




二、使用“+=”符号拼接


在python语言中“+=”符号与“+”符号拼接存在实质的区别。所以,我也试着在


java中实验看看:
public static void b(){
long starTime = new Date().getTime();
String string = new String();
for(int i=0;i<50000;i++){
string += i;
}
long endTime = new Date().getTime();
System.out.println("“+=”号花费时间:"+(endTime - starTime));
}
这种方式花费的时间大致与“+”号拼接相同,也在6800毫秒左右。如果有对python比较熟悉的,可以分别运行看一下。




三、使用concat方法拼接


直接看代码:
public static void e(){
long starTime = new Date().getTime();
String string = new String();
for(int i=0;i<50000;i++){
string = string.concat(String.valueOf(i));
}
long endTime = new Date().getTime();
System.out.println("concat花费时间:"+(endTime - starTime));
}
这种方式花费的时间在2400毫秒左右。




四、使用StringBuffer方式拼接


为了保证足够的严谨,我在这个实验中同样新建了一个String类型的对象。下面


是实验代码:
public static void c(){
long starTime = new Date().getTime();
String string = new String();
StringBuffer stringb = new StringBuffer();
for(int i=0;i<50000;i++){
stringb = stringb.append(i);
}
string = string + stringb;
long endTime = new Date().getTime();
System.out.println("StringBuffer花费时间:"+(endTime - starTime));
}
这种方式花费的时间在37毫秒左右。




五、使用StringBuilder方式拼接


实验代码:
public static void d(){
long starTime = new Date().getTime();
String string = new String();
StringBuilder stringb = new StringBuilder();
for(int i=0;i<50000;i++){
stringb = stringb.append(i);
}
string = string + stringb;
long endTime = new Date().getTime();
System.out.println("StringBuilder花费时间:"+(endTime - starTime));
}
这种方式花费的时间也在37毫秒左右。由于5万次拼接对于StringBuffer和StringBuilder来说没什么区别,所以我把执行次数增加到了500万次。在500万次的执行中StringBuffer花费大约627毫秒;StringBuilder花费大约418毫秒。

这里我需要说明一点,我的实验环境都是在单线程情况下进行的。如果在多线程中StringBuilder的速度要明显优于StringBuffer。原因就在于StringBuffer内部的实现都加上了synchronized关键字,保证了线程安全的同时也因此降低了效率。下面是StringBuffer和StringBuffer拼接实现源码:

    @Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }




“+”号拼接与concat方法拼接的区别


首先来看JDK中String类中concat方法的源码:
public static void d(){
long starTime = new Date().getTime();
String string = new String();
StringBuilder stringb = new StringBuilder();
for(int i=0;i<50000;i++){
stringb = stringb.append(i);
}
string = string + stringb;
long endTime = new Date().getTime();
System.out.println("StringBuilder花费时间:"+(endTime - starTime));
}
通过上面的源码我们可以发现,concat方法通过确认两个字符串中字符的个数新建一个字符数组。
    void getChars(char dst[], int dstBegin) {
        System.arraycopy(value, 0, dst, dstBegin, value.length);
    }
最后再通过构造函数创建一个新的String对象。


“+”号方式拼接博主查阅了很多资料。通过反编译class文件最后发现“+”号拼接其实是用StringBuilder来实现的。那么又带来了一个疑问,如果是使用StringBuilder方式实现的话,那为什么它的性能如此之差呢?


带着这个疑问我把“+”号底层实现代码与第一次实验中的“+”号进行了替换:
public static void a(){
long starTime = new Date().getTime();
String string = new String();
for(int i=0;i<50000;i++){
StringBuilder sb = new StringBuilder();
sb.append(string).append(String.valueOf(i));
string = sb.toString();
}
long endTime = new Date().getTime();
System.out.println("“+”号底层替换花费时间:"+(endTime - starTime));
}
这段代码花费了9000毫秒左右。而且在大量的拼接过程中会反复的创建StringBuilder对象。




思考一下,“+”号拼接在任何情况下性能都低于StringBuilder吗?



答案:当然不是。


String string = "Hua" + "PL";
在上面这种字符串拼接中“+”号的速度简直领人惊叹。同样我也进行了实验。由于他们的执行速度过快,我把执行次数依然调到了500万次。下面是实验的两段代码:
public static void a(){
long starTime = new Date().getTime();
for(int i=0;i<5000000;i++){
String string = "Hua" + "PL";
}
long endTime = new Date().getTime();
System.out.println("“+”号花费时间:"+(endTime - starTime));
}
public static void d(){
long starTime = new Date().getTime();
for(int i=0;i<5000000;i++){
StringBuilder string = new StringBuilder("Hua");
string = string.append("PL");
}
long endTime = new Date().getTime();
System.out.println("StringBuilder花费时间:"+(endTime - starTime));
}
这种方式的拼接,“+”号方式只用了10毫秒;而StringBuilder用了314毫秒

你可能感兴趣的:(字符串拼接多种实现方式及性能详解)