zoukankan      html  css  js  c++  java
  • Java 字符串拼接四种方式的性能比较分析

    一、简单介绍

    编写代码过程中,使用"+"和"contact"比较普遍,但是它们都不能满足大数据量的处理,一般情况下有一下四种方法处理字符串拼接,如下:

    1、 加号"+"

    2、 Stringcontact()方法

    3、 StringBufferappend()方法

    4、 StringBuilderappend()方法

    二、测试代码参考

    StringTest

    package com.jdk8.event.StringTest;
    
    public class StringTest {
        private static final int max = 100000;
    
        public static void testPlus() {
            System.out.println("************ plusTest() ************");
    
            String str = "";
    
            long start = System.currentTimeMillis();
    
            for (int i = 0; i < max; i++) {
                str = str + "a";
            }
    
            long end = System.currentTimeMillis();
    
            long cost = end - start;
    
            System.out.println("   {str + "a"} cost=" + cost + " ms");
        }
    
        public  static  void testConcat() {
            System.out.println("************ concatTest() ************");
    
            String str = "";
    
            long start = System.currentTimeMillis();
    
            for (int i = 0; i < max; i++) {
                str = str.concat("a");
            }
    
            long end = System.currentTimeMillis();
    
            long cost = end - start;
    
            System.out.println("   {str.concat("a")} cost=" + cost + " ms");
        }
    
        public  static  void testStringBuffer() {
            System.out.println("************ StringBufferTest() ************");
    
            long start = System.currentTimeMillis();
    
            StringBuffer strBuffer = new StringBuffer();
    
            for (int i = 0; i < max; i++) {
                strBuffer.append("a");
            }
            strBuffer.toString();
    
            long end = System.currentTimeMillis();
    
            long cost = end - start;
    
            System.out.println("   {strBuffer.append("a")} cost=" + cost + " ms");
        }
    
        public  static  void testStringBuilder() {
            System.out.println("************ StringBuilderTest() ************");
    
            long start = System.currentTimeMillis();
    
            StringBuilder strBuilder = new StringBuilder();
    
            for (int i = 0; i < max; i++) {
                strBuilder.append("a");
            }
            strBuilder.toString();
    
            long end = System.currentTimeMillis();
    
            long cost = end - start;
    
            System.out.println("   {strBuilder.append("a")} cost=" + cost + " ms");
        }
    }
    

    测试类:TestMain

    package com.jdk8.event.StringTest;
    
    public class TestMain {
        public static void main(String[] args){
            System.out.println("执行100次时");
            StringTest.testPlus();
            StringTest.testConcat();
            StringTest.testStringBuffer();
            StringTest.testStringBuilder();
        }
    }
    

    测试结果如下:

    执行100次时
    ************ plusTest() ************
       {str + "a"} cost=0 ms
    ************ concatTest() ************
       {str.concat("a")} cost=0 ms
    ************ StringBufferTest() ************
       {strBuffer.append("a")} cost=0 ms
    ************ StringBuilderTest() ************
       {strBuilder.append("a")} cost=0 ms
    
    执行1000次时
    ************ concatTest() ************
       {str.concat("a")} cost=1 ms
    ************ StringBufferTest() ************
       {strBuffer.append("a")} cost=0 ms
    ************ StringBuilderTest() ************
       {strBuilder.append("a")} cost=0 ms
    
    执行10000次时
    ************ plusTest() ************
       {str + "a"} cost=99 ms
    ************ concatTest() ************
    Disconnected from the target VM, address: '127.0.0.1:63818', transport: 'socket'
       {str.concat("a")} cost=17 ms
    ************ StringBufferTest() ************
       {strBuffer.append("a")} cost=1 ms
    ************ StringBuilderTest() ************
       {strBuilder.append("a")} cost=0 ms
    
    执行100000次时
    ************ plusTest() ************
       {str + "a"} cost=6176 ms
    ************ concatTest() ************
       {str.concat("a")} cost=1267 ms
    ************ StringBufferTest() ************
       {strBuffer.append("a")} cost=3 ms
    ************ StringBuilderTest() ************
    Disconnected from the target VM, address: '127.0.0.1:63841', transport: 'socket'
       {strBuilder.append("a")} cost=2 ms
    
    执行300000次时
    ************ plusTest() ************
       {str + "a"} cost=23554 ms
    ************ concatTest() ************
       {str.concat("a")} cost=17667 ms
    ************ StringBufferTest() ************
       {strBuffer.append("a")} cost=6 ms
    ************ StringBuilderTest() ************
       {strBuilder.append("a")} cost=5 ms
    
    执行500000次时
    ************ plusTest() ************
       {str + "a"} cost=61421 ms
    ************ concatTest() ************
       {str.concat("a")} cost=53173 ms
    ************ StringBufferTest() ************
       {strBuffer.append("a")} cost=9 ms
    ************ StringBuilderTest() ************
       {strBuilder.append("a")} cost=7 ms
    

    1、 方法1 "+"号和方法2 contact()方法适用于数据量比较小的情况下。为了操作代码风格和养成习惯,还是建议尽量不用

    2、方法2 StringBufferappend()方法和StringBuilderappend()方法 本质上是一样的,均继承自AbstractStringBuilder抽象类,效率很高,数据量比较大的时候的推荐用法。区别是StringBuffer 是线程安全的,而StringBuilder是线程不安全的。

    三、源代码分析

    1、 String的"+"方法,编译器对其做了优化,使用StringBuilderappend()方法进行追加,但是每循环一次都会创建一个StringBuilder对象,且都会调用toString()方法转换为字符串,因此开销很大。

    注:执行一次String的"+"方法,相当于str = new StringBuilder(str).append("x").toString();

    2、调用Stringcontact()方法,其实就是一次数组的拷贝,虽然在内存中的处理都是原子操作,速度很快,但是当返回时是要创建一个新的String对象的,这样不仅限制了效率,更添加了空间的压力,源码如下:

        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);
        }
    

    3、StringBufferStringBuilderappend()方法均主要使用父类AbstractStringBuilderappend()方法。源码如下:

        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;
        }
    

    即当数组空间够用的时候,只是在数组后面添加字符或字符串,并不创建新的对象,只是到最后通过toString()方法来生成最终的字符串,效率很快,也很节省空间,是推荐的用法。

    参考

    https://www.cnblogs.com/twzheng/p/5923642.html

  • 相关阅读:
    odoo10 按钮点击时的弹窗提示确认消息
    odoo10 行表创建新数据时默认取值
    odoo10 关于ODOOsearch视图
    odoo10 many2one字段下拉更多选项时自定义排序方法
    变量的注释(python3.6以后的功能)
    蓝图的使用
    线程
    基础总结1
    请求上下文和应用上下文
    flask-script扩展
  • 原文地址:https://www.cnblogs.com/ITBlock/p/10231030.html
Copyright © 2011-2022 走看看