• 字符串拼接的几种方式和区别


    文章来源:http://hollischuang.gitee.io/tobetopjavaer/#/basics/java-basic/string-concat

    结论:

    1.使用StringBuilder的方式是效率最高的。

    2.如果不是在循环体中进行字符串拼接的话,直接使用+就好了。

    3.如果在并发场景中进行字符串拼接的话,要使用StringBuffer来代替StringBuilder

    使用+拼接字符串

    在Java中,拼接字符串最简单的方式就是直接使用符号+来拼接。如:

    String wechat = "Hollis"; 
    String introduce = "每日更新Java相关技术文章";
    String hollis = wechat + "," + introduce;

    反编译后的内容如下

    String wechat = "Hollis";
    String introduce = "u6BCFu65E5u66F4u65B0Javau76F8u5173u6280u672Fu6587u7AE0";//每日更新Java相关技术文章
    String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();

    通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使用其append方法进行处理的。

    那么也就是说,Java中的+对字符串的拼接,其实现原理是使用StringBuilder.append

    concat

    使用String类中的方法concat方法来拼接字符串。如:

    String str1 = "aaa";
    String str2 = "bbb";
    String str = str1.concat(",").concat(str2);

    看一下concat方法的源代码,看一下这个方法又是如何实现的。

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

    这段代码首先创建了一个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,并使用这个字符数组创建一个新的String对象并返回。

    通过源码我们也可以看到,经过concat方法,其实是new了一个新的String

    StringBuffer

    可以用来定义字符串变量的StringBuffer类,它的对象是可以扩充和修改的。

    使用StringBuffer可以方便的对字符串进行拼接。如:

    StringBuffer sb1 = new StringBuffer("aaa");
    String str1 = "bbb";
    StringBuffer sb2 = sb1.append(",").append(str1);

    StringBuilder

    还有一个类StringBuilder也可以使用,其用法和StringBuffer类似。如:

    StringBuilder sb1 = new StringBuilder("aaa");
    String str1 = "bbb";
    StringBuilder sb2= sb1 .append(",").append(str1 );

    看看StringBufferStringBuilder的实现原理。

    String类类似,StringBuilder类也封装了一个字符数组,定义如下:

    char[] value;
    

    String不同的是,它并不是final的,所以他是可以修改的。另外,与String不同,字符数组中不一定所有位置都已经被使用,它有一个实例变量,表示数组中已经使用的字符个数,定义如下:

    int count;
    

    其append源码如下:

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

    该类继承了AbstractStringBuilder类,看下其append方法:

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

    append会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进行扩展。

    StringBufferStringBuilder类似,最大的区别就是StringBuffer是线程安全的,看一下StringBufferappend方法。

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

    该方法使用synchronized进行声明,说明是一个线程安全的方法。而StringBuilder则不是线程安全的。

    为什么不建议在循环体中使用+进行字符串拼接呢?

    效率比较

    既然有这么多种字符串拼接的方法,那么到底哪一种效率最高呢?我们来简单对比一下。

    long t1 = System.currentTimeMillis();
    //这里是初始字符串定义
    for (int i = 0; i < 50000; i++) {
        //这里是字符串拼接代码
    }
    long t2 = System.currentTimeMillis();
    System.out.println("cost:" + (t2 - t1));
    

    我们使用形如以上形式的代码,分别测试下五种字符串拼接代码的运行时间。得到结果如下:

    + cost:5119
    StringBuilder cost:3
    StringBuffer cost:4
    concat cost:3623
    

    从结果可以看出,用时从短到长的对比是:

    StringBuilder<StringBuffer<concat<+

    StringBufferStringBuilder的基础上,做了同步处理,所以在耗时上会相对多一些。

    其实使用+拼接字符串的实现原理也是使用的StringBuilder,那为什么结果相差这么多,因为在for循环中,每次都是new了一个StringBuilder,然后再把String转成StringBuilder,再进行append

    而频繁的新建对象当然要耗费很多时间了,不仅仅会耗费时间,频繁的创建对象,还会造成内存资源的浪费。

    总结

    虽然字符串是不可变的,但是还是可以通过新建字符串的方式来进行字符串的拼接。

    由于字符串拼接过程中会创建新的对象,所以如果要在一个循环体中进行字符串拼接,就要考虑内存问题和效率问题。

    因此,经过对比,我们发现,直接使用StringBuilder的方式是效率最高的。因为StringBuilder天生就是设计来定义可变字符串和字符串的变化操作的。

  • 相关阅读:
    PTA —— 基础编程题目集 —— 函数题 —— 61 简单输出整数 (10 分)
    PTA —— 基础编程题目集 —— 函数题 —— 61 简单输出整数 (10 分)
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    练习2.13 不用库函数,写一个高效计算ln N的C函数
    迷宫问题 POJ 3984
    UVA 820 Internet Bandwidth (因特网带宽)(最大流)
    UVA 1001 Say Cheese(奶酪里的老鼠)(flod)
    UVA 11105 Semiprime Hnumbers(H半素数)
    UVA 557 Burger(汉堡)(dp+概率)
  • 原文地址:https://www.cnblogs.com/ooo0/p/12779705.html
Copyright © 2020-2023  润新知