Java字符串拼接那些事

300 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第19天,点击查看活动详情

1. 代码中字符串最常用的拼接方法

  • + 拼接
  • apache 的工具类 StringUtils.join 方法
  • String 类的对象方法 concat
  • StringBuffer 类的对象方法 append
  • StringBuilder 类的对象方法 append

等等一些组合方式。以上几种是编码过程中最常见的。下面就来看看这几种方式的字符串拼接的实现和效率

2. + 操作符的拼接

public class StringConcatTest {

    public static void main(String[] args) {
        String wc = "aaaaa";
        String wc1 = "bbbbbb";
        String ct = wc + "," + wc1;
    }

}

查看 .class 文件后的反编译代码如下

package com.mxsm.cglib.enhancer;

public class StringConcatTest {
    public StringConcatTest() {
    }

    public static void main(String[] args) {
        String wc = "aaaaa";
        String wc1 = "bbbbbb";
        (new StringBuilder()).append(wc).append(",").append(wc1).toString();
    }
}

代码 String ct = wc + "," + wc1; —> (new StringBuilder()).append(wc).append(",").append(wc1).toString();

转换成了 StringBuilderappend 方法。

在阿里巴巴的Java开发手册中不建议循环体中使用 + 进行字符串拼接原因是什么?

原因就在于 + 每次创建一个 StringBuilder 对象然后 toString() 返回字符串对象,造成内存资源的浪费

3. Stringconcat 方法

public class StringConcatTest {
    public static void main(String[] args) {
        String wc = "aaaaa";
        String wc1 = "bbbbbb";
        String ct = wc.concat(",").concat(wc1);
    }
}

接下来看一下 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);
    	//返回一个new String的新对象
        return new String(buf, true);
    }

4. StringBufferStringBuilderappend 方法

  • StringBufferappend 方法

        @Override
        public synchronized StringBuffer append(String str) {
            toStringCache = null;
            //调用的是父类的append方法
            super.append(str);
            return this;
        }
     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;
        }
    

    注意:StringBufferappend 方法带有关键字 synchronized 说明是线程安全的。

  • StringBuilderappend 方法

    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    
     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;
        }
    

从上面的源码可以看出来 StringBufferStringBuilder 的底层实现都是 调用了父类 AbstractStringBuilder 的 **append**方法。唯一的区别就是 StringBuffer 线程安全 , StringBuilder 非线程安全。所以想要线程安全 就用 StringBuffer 没有线程安全的问题的考虑就用 StringBuilder

5. StringUtils.join

这里源码自行参考 apache 工具类 的源码

6. 各自的效率

重中之重的来了,那就是各个方法的拼接效率怎么样?为什么阿里巴巴的Java规范中不提倡用 + 进行字符串拼接

下面我们上代码来说明明天,看看到底谁牛逼速度快。

public class StringConcatTest {

    public static void main(String[] args) {

        int count = 66666;

        long t1 = System.currentTimeMillis();
        String s1 = "1";
        for(int i = 0; i < count; ++i){
            s1 = s1 + "1";
        }
        System.out.println("+ "+(System.currentTimeMillis()-t1)+"ms");


        long t2 = System.currentTimeMillis();
        StringBuffer s2 = new StringBuffer("1");
        for(int i = 0; i < count; ++i){
            s2.append("1");
        }
        System.out.println("StringBuffer "+(System.currentTimeMillis()-t2)+"ms");

        long t3 = System.currentTimeMillis();
        StringBuilder s3 = new StringBuilder("1");
        for(int i = 0; i < count; ++i){
            s3.append("1");
        }
        System.out.println("StringBuilder "+(System.currentTimeMillis()-t3)+"ms");

        long t4 = System.currentTimeMillis();
        String s4 = "1";
        for(int i = 0; i < count; ++i){
            s4 = s4.concat("1");
        }
        System.out.println("concat "+(System.currentTimeMillis()-t4)+"ms");

    }

}

运行的打印结果:

+ 2949ms
StringBuffer 2ms
StringBuilder 1ms
concat 693ms

我是蚂蚁背大象,文章对你有帮助点赞关注我,文章有不正确的地方请您斧正留言评论~谢谢!