java提高篇(十三)-----字符串(二)

2014-11-24 07:32:09 · 作者: · 浏览: 2
析成StringBuilder对象拼接,在这种情况下String的速度比StringBuffer的速度快。如:

String name = ”I ” + ”am ” + ”chenssy ” ;

StringBuffer name = new StringBuffer(”I ”).append(” am ”).append(” chenssy ”);

对于这两种方式,你会发现第一种比第二种快太多了,在这里StringBuffer的优势荡然无存。其真实的原因就在于JVM做了一下优化处理,其实String name = ”I ” + ”am ” + ”chenssy ” ;在JVM眼中就是String name = ”I am chenssy ” ;这样的方式对于JVM而言,真的是不要什么时间。但是如果我们在这个其中增加一个String对象,那么JVM就会按照原来那种规范来构建String对象了。

对于这三者使用的场景做如下概括(参考:《编写搞质量代码:改善java程序的151个建议》):

1、String:在字符串不经常变化的场景中可以使用String类,如:常量的声明、少量的变量运算等。

2、StringBuffer:在频繁进行字符串的运算(拼接、替换、删除等),并且运行在多线程的环境中,则可以考虑使用StringBuffer,例如XML解析、HTTP参数解析和封装等。

3、StringBuilder:在频繁进行字符串的运算(拼接、替换、删除等),并且运行在多线程的环境中,则可以考虑使用StringBuffer,如SQL语句的拼装、JSON封装等(貌似这两个我也是使用|StringBuffer)。

更多有关于他们之间区别,请参考:http://www.cnblogs.com/zuoxiaolong/p/lang1.html。鄙人就不画蛇添足了。

五、字符串拼接方式

对于字符串而言我们经常是要对其进行拼装处理的,在java中提高了三种拼装的方法:+、concat()以及append()方法。这三者之间存在什么区别呢?先看如下示例:

public class StringTest {
    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void
     */
    public static void main(String[] args) {
        //+
        long start_01 = System.currentTimeMillis();
        String a = a;
        for(int i = 0 ; i < 100000 ; i++){
            a += b;
        }
        long end_01 = System.currentTimeMillis();
        System.out.println(  +   所消耗的时间: + (end_01 - start_01) + 毫米);
        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = c;
        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat(d);
        }
        long end_02 = System.currentTimeMillis();
        System.out.println(concat所消耗的时间: + (end_02 - start_02) + 毫米);
        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer(e);
        for(int i = 0 ; i < 100000 ; i++){
            e.append(d);
        }
        long end_03 = System.currentTimeMillis();
        System.out.println(append所消耗的时间: + (end_03 - start_03) + 毫米);
    }
}

------------
Output:
  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米

public class StringTest {
    
    /**
     * @desc 使用+、concat()、append()方法循环10W次
     * @author chenssy
     * @data 2013-11-16
     * @param args
     * @return void
     */
    public static void main(String[] args) {
        //+
        long start_01 = System.currentTimeMillis();
        String a = a;
        for(int i = 0 ; i < 100000 ; i++){
            a += b;
        }
        long end_01 = System.currentTimeMillis();
        System.out.println(  +   所消耗的时间: + (end_01 - start_01) + 毫米);
        
        //concat()
        long start_02 = System.currentTimeMillis();
        String c = c;
        for(int i = 0 ; i < 100000 ; i++){
            c = c.concat(d);
        }
        long end_02 = System.currentTimeMillis();
        System.out.println(concat所消耗的时间: + (end_02 - start_02) + 毫米);
        
        //append
        long start_03 = System.currentTimeMillis();
        StringBuffer e = new StringBuffer(e);
        for(int i = 0 ; i < 100000 ; i++){
            e.append(d);
        }
        long end_03 = System.currentTimeMillis();
        System.out.println(append所消耗的时间: + (end_03 - start_03) + 毫米);
    }
}

------------
Output:
  +   所消耗的时间:19080毫米
concat所消耗的时间:9089毫米
append所消耗的时间:10毫米
从上面的运行结果可以看出,append()速度最快,concat()次之,+最慢。原因请看下面分解:

(一)+方式拼接字符串

在前面我们知道编译器对+进行了优化,它是使用StringBuilder的append()方法来进行处理的,我们知道StringBuilder的速度比StringBuffer的速度更加快,但是为何运行速度还是那样呢?主要是因为编译器使用append()方法追加后要同toString()转换成String字符串,也就说 str +=”b”等同于

str = new StringBuilder(str).append(b).toString();

它变慢的关键原因就在于new StringBuilder()和toString(),这里可是创建了10W个StringBuilder对象,而且每次还需要将其转换成String,速度能不慢么?

(二)concat()方法拼接字符串

public String concat(String str) {
    int otherLen = str.length();
    if (otherLen == 0) {
        return this;
    }
    char buf[] = new char[count + otherLen];
    getChars(0, count, buf, 0);
    str.getChars(0, otherLen, buf, count);
    return new String(0, count + otherLen, buf);
    }

这是concat()的源码,它看上去就是一个数字拷贝形式,我们知道数组的处理速度是非常快的,但是由于该方法最后是这样的:return new String(0, count + otherLen, buf);这同样也创建了10W个字符串对象,这是它变慢的根本原因。

(三)append()方法拼接字符串

public synchronized StringBuffer append(String str) {
    super.append(str);
        return this;
    }

StringBuffer的append()方法是直接使用父类AbstractStringBuilder的append()方法,该方法的源码如下:

public AbstractStringBuilder append(String str) {
    if (str == null) str = null;
        int len = str.length();
    if (len == 0) return this;
    int newCount = count + len;
    if (newCount > value.length)
        expandCapacity(newCount);
    str.getChars(0, len, value, count);
    count = newCount;
    return this;
    }

与concat()方法相似,它也是进行字符数组处理的,加长,然后拷贝,但是请注意它最后是返回并没有返回一个新串,而是返回本身,也就说这这个10W次的循环过程中,它并没有产生新的字符串对象。

通过上面的分析,我们需要在合适的场所选择合适的字符串拼接方式,但是并不一定就要选择append()和concat()方法,原因在于+根据符合我们的编程习惯,只有到了使用append()和concat()方法确实是可以对我们系统的效率起到比较大的帮助,才会考虑,同时鄙人也真的没有怎么用过concat()方法。