五千年(敝帚自珍)

主题:【倡议】Java SE 5.0和.NET 2.0擂台赛 -- Highway

共:💬34
全看分页树展 · 主题 跟帖
家园 String, StringBuffer &StringBuilder的玄妙

String可能是使用最广泛的一种操作了,尤其是在现在Web程序开发中。事实上,Java的String是非常特殊的一种Class,即所有的String Object都是Immutable的。为什么要这样对待String呢?因为Sun想尽可能的榨取一切可能的性能。

为了提高连续拼接String的性能,Java提供了一个类叫StringBuffer。使用它在某些情况下可以成千倍的提高性能。但是Sun还是不够满意,在Java 5.0中,它又提供了一个类叫做StringBuilder。

那么StringBuilder和StringBuffer有什么区别呢?StringBuffer是Thread-safe的,而StringBuilder不是。

那么什么是Thread-safe呢?还记得国内火车内的那种厕所吗?一个人进去,把门一锁,然后开始“方便”。其间不会被外人打扰。完事后开门出来,下一个人才能进去。不会有两个人同时一起“方便”的尴尬局面。这就是Thread-safe.显然Thread-safe有一定的开销,比如关门,上锁,开门等等。在有些情况下,我们不需要这么safe,比如在家里(如果只有你和你老婆),或者你是单身汉,家里根本就没外人。在这种情况下,不用Thread-safe可能会更方便一些,效率会更高。

StringBuilder就是这样的设计思想。在一切可能的情况下使用StringBuilder,最大限度的提高性能。

大家看看下面这段小程序,就会有些感性认识了。

源程序

......
        String[] strs = null;
        strs = this.prepareString(5000);
        this.stringBufferTest(strs);
        this.stringBuilderTest(strs);
        this.stringTest(strs);
        
        strs = this.prepareString(20000);
        this.stringBufferTest(strs);
        this.stringBuilderTest(strs);
        //this.stringTest(strs);
        
        strs = this.prepareString(100000);
        this.stringBufferTest(strs);
        this.stringBuilderTest(strs);
        //this.stringTest(strs);    
......
    private String[] prepareString(int number){
        System.out.println("String number: " + number);
        String[] strs = new String[number];
        for(int i=0; i<number; i++)
            strs[i] = "Highway" + i;
        return strs;
    }
    private void stringBuilderTest(String[] input){
        long start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for(int i=0; i<input.length; i++)
            sb.append(input[i]);
        long time = System.currentTimeMillis()-start;
        System.out.println("StringBuilder Takes Time: " + time + "ms");
        return;
    }
    private void stringBufferTest(String[] input){
        long start = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer();
        for(int i=0; i<input.length; i++)
            sb.append(input[i]);
        long time = System.currentTimeMillis()-start;
        System.out.println("StringBuffer Takes Time: " + time+ "ms");
        return;
    }
    private void stringTest(String[] input){
        long start = System.currentTimeMillis();
        String sb = "";
        for(int i=0; i<input.length; i++)
            sb = sb + input[i];
        long time = System.currentTimeMillis()-start;
        System.out.println("String Append Takes Time: " + time+ "ms");
        return;
    }    

反编译得到的程序,这是Java实际工作的Code.

    private String[] prepareString(int number)
    {
        System.out.println((new StringBuilder()).append("String number: ").append(number).toString());
        String strs[] = new String[number];
        for(int i = 0; i < number; i++)
            strs[i] = (new StringBuilder()).append("Highway").append(i).toString();

        return strs;
    }

    private void stringBuilderTest(String input[])
    {
        long start = System.currentTimeMillis();
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < input.length; i++)
            sb.append(input[i]);

        long time = System.currentTimeMillis() - start;
        System.out.println((new StringBuilder()).append("StringBuilder Takes Time: ").append(time).append("ms").toString());
    }

    private void stringBufferTest(String input[])
    {
        long start = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer();
        for(int i = 0; i < input.length; i++)
            sb.append(input[i]);

        long time = System.currentTimeMillis() - start;
        System.out.println((new StringBuilder()).append("StringBuffer Takes Time: ").append(time).append("ms").toString());
    }

    private void stringTest(String input[])
    {
        long start = System.currentTimeMillis();
        String sb = "";
        for(int i = 0; i < input.length; i++)
            sb = (new StringBuilder()).append(sb).append(input[i]).toString();

        long time = System.currentTimeMillis() - start;
        System.out.println((new StringBuilder()).append("String Append Takes Time: ").append(time).append("ms").toString());
    }

由上可见,Java在内部尽可能的在使用StringBuilder

[SIZE=3]测试结果:[/SIZE]

String number: 5000
StringBuffer Takes Time: 15ms
StringBuilder Takes Time: 0ms
String Append Takes Time: 7281ms
String number: 20000
StringBuffer Takes Time: 31ms
StringBuilder Takes Time: 16ms
String number: 100000
StringBuffer Takes Time: 188ms
StringBuilder Takes Time: 156ms

由此可见,StringBuilder 确实是有效果的。最慢的是String直接拼接,效果满上千倍,这是大家应该避免的情况。

那么.NET如何呢?.NET只有一个StringBuilder,没有StringBuffer。这个StringBuilder的Public static变量是Thread-safe的,而instance members却不是。哈哈,有意思吧!!!

将上面Java的程序用.NET写一遍,其运行结果比Java快很多,尤其是赤裸裸的SString拼接(20倍)。这是一个很有趣的问题。希望大家能帮我解释一下为什么!!!

String number: 5000
StringBuilder Takes Time: 0ms
String Append Takes Time: 422ms
String number: 20000
StringBuilder Takes Time: 15ms
String number: 100000
StringBuilder Takes Time: 32ms

C#源程序为:

        private String[] prepareString(int number)
        {
            System.Console.WriteLine("String number: " + number);
            String[] strs = new String[number];
            for(int i=0; i<number; i++)
                strs[i] = "Highway" + i;
            return strs;
        }
        private void stringBuilderTest(String[] input)
        {
            long start = System.Environment.TickCount;
            StringBuilder sb = new StringBuilder();
            for(int i=0; i<input.Length; i++)
                sb.Append(input[i]);
            long time = System.Environment.TickCount - start;
            System.Console.WriteLine("StringBuilder Takes Time: " + time + "ms");
            return;
        }

        private void stringTest(String[] input)
        {
            long start = System.Environment.TickCount;
            String sb = "";
            for(int i=0; i<input.Length; i++)
                sb = sb + input[i];
            long time = System.Environment.TickCount - start;
            System.Console.WriteLine("String Append Takes Time: " + time + "ms");
            return;
        }

反编译后为:

private void stringBuilderTest(string[] input)
{
      long num1 = Environment.TickCount;
      StringBuilder builder1 = new StringBuilder();
      for (int num2 = 0; num2 < input.Length; num2++)
      {
            builder1.Append(input[num2]);
      }
      long num3 = Environment.TickCount - num1;
      Console.WriteLine("StringBuilder Takes Time: " + num3 + "ms");
}
 
private void stringTest(string[] input)
{
      long num1 = Environment.TickCount;
      string text1 = "";
      for (int num2 = 0; num2 < input.Length; num2++)
      {
            text1 = text1 + input[num2];
      }
      long num3 = Environment.TickCount - num1;
      Console.WriteLine("String Append Takes Time: " + num3 + "ms");
}

全看分页树展 · 主题 跟帖


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河