码迷,mamicode.com
首页 > 编程语言 > 详细

java中String和StringBuffer哪个效率高

时间:2015-05-17 10:52:54      阅读:166      评论:0      收藏:0      [点我收藏+]

标签:stringbuffer   string   java效率   

大多数的网站以及多数的java书上都会说使用StringBuffer类进行字符串”连接”操作是比String类进行连接操作的效率高的,那么真的是这样吗?在这里我们实际自己测试一下,看看他们两个到底谁的效率高,然后从反编译的代码解释原因.

在我的这篇博客:《Java中 “abc” + ‘/’和”abc” + “/”的区别》中提到了String类的’+’操作是依赖于StringBuilder类的,而JDK API文档中说StringBuilder类的速度是比StringBuffer类更快的.那么到底是String类的效率高还是StringBuffer类的效率高呢?这里我们自己测试一下.

程序的大体框架

import java.util.*;

public class StringTest{
    private static final int COUNT = 50000;

    public static void main(String[] args) {
        Runtime run = Runtime.getRuntime();
        long startTime, endTime;
        long startMem, endMem;

        // 回收一下垃圾
        run.gc();
        // 记录开始时的内存及时间信息,并打印到屏幕上
        startTime = System.currentTimeMillis();
        startMem = run.totalMemory() - run.freeMemory();
        System.out.println( "time: " + (new Date()) );
        System.out.println("used memory: " + startMem);

        // 执行需要测试的代码段
        test();

        // 计算花费的内存及时间,然后打印到屏幕上
        endTime = System.currentTimeMillis();
        endMem = run.totalMemory() - run.freeMemory();
        System.out.println("time: " + (new Date()) + ", spend time:" + (endTime-startTime));
        System.out.println("used memory: " + endMem + ", added memory:" + (endMem-startMem));
    }

    public static String test(){
        // 这里写String的连接操作或者StringBuffer的"连接"操作
    }
}
  • System.currentTimeMillis();可以得到以毫秒为单位的当前时间,所以endTime-startTime大致就是test方法运行的时间.因为两次获取时间当中不仅执行了test方法还获取了系统内存,以及打印了两条信息.
  • run.totalMemory() - run.freeMemory()可以大致获取程序当前使用使用的内存,在这里我们就不解释了,有不明白的可以参考我的另一篇博客:《获取java程序运行时内存信息》.

这个大致的框架没有什么比较难以理解的地方,所以,就只解释这两条吧.下面我们把test方法补充完整

待测试部分的程序代码

需要测试的代码非常简单:
String类测试代码

public static String test(){
    String str = "";
    for(int i=0; i<COUNT; ++i){
        str += i;
    }
    return str;
}

StringBuffer类测试代码

public static String test(){
    StringBuffer strbf = new StringBuffer();
    for(int i=0; i<COUNT; ++i){
        strbf.append(i);
    }
    return strbf.toString();
}

貌似没法让这两段代码并排显示…将就着看吧
这段程序就是简单的从0连接到49999,我们创建两个类,分别用这两段代码填充就可以开始测试了.OK,一切准备就绪,那么下面就是运行程序,查看输出结果了吧?

运行结果

左边的图是测试String类的输出结果,右边是测试StringBuffer的结果:

技术分享 String类的测试结果
技术分享 StringBuffer类的测试结果

额,好吧,虽然和《Java中 “abc” + ‘/’和”abc” + “/”的区别》里边的猜测完全相反,但是也不得不承认StringBuffer类确实比String类更快.那么,为什么呢?String类的连接不是依赖于StringBuilder类的吗?

从反编译的源码解释这个现象

由于反编译的代码会比较长,这里我们只给出测试String类的testfor循环部分的代码.如果对测试StringBuffer类的for循环部分感兴趣,请自己查看.
执行下面的命令,就可以在StringTest.s中看到反编译的代码:

javap -c StringTest.class > StringTest.s

 6: ldc           #24                 // int 50000
 8: if_icmpge     36
11: new           #8                  // class java/lang/StringBuilder
14: dup
15: invokespecial #9                  // Method java/lang/StringBuilder."<init>":()V
18: aload_0
19: invokevirtual #11                 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
22: iload_1
23: invokevirtual #25                 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
26: invokevirtual #15                 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
29: astore_0
30: iinc          1, 1
33: goto          5

如果把这段代码翻译成java代码就是下面这段代码:

for(int i=0; i<COUNT; ++i){
    str = new StringBuilder().append(str).append(i).toString();
}

注:上面这段程序确实和我们最开始给出的程序一样,连反编译产生的代码都一模一样

也就是每连接一次字符串都会产生一个临时的StringBuilder对象,同时还会舍弃以前的String对象,所以在内存上会有很大的开销.由于拷贝字符串到新的数组,构造2n个对象以及使用内存过大导致更频繁的缺页等也导致了String类连接字符串在时间上也比StringBuffer类差了许多倍.所以在有较大量的字符串连接时使用StringBuilder或者StringBuffer好处还是挺好的.当然,在字符串连接比较少的情况下使用StringStringBuffer方便不少,又不会有过多的性能问题,所以完全可以使用String类.
事实证明,String类比StringBuffer类快只是我一厢情愿而已.但是也得到了一些经验:有什么猜想就应该去动手验证它,即使结果可能和我们所猜想差了十万八千里,否则你永远不知道/不相信真正的答案是什么.

写于 2015/05/17

java中String和StringBuffer哪个效率高

标签:stringbuffer   string   java效率   

原文地址:http://blog.csdn.net/u011004037/article/details/45786379

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!