zoukankan      html  css  js  c++  java
  • 阿里巴巴Java开发手册_不建议在循环体中使用+进行字符串拼接

    18. 【推荐】循环体内,字符串的连接方式,使用StringBuilder的append方法进行扩展。
    说明:下例中,反编译出的字节码文件显示每次循环都会new出一个StringBuilder对象,然后进行append操作,
    最后通过toString方法返回String对象,造成内存资源浪费。
    反例:
    String str = "start";
    for (int i = 0; i < 100; i++) {
    str = str + "hello";
    }

    1.String是Java中一个不可变的类,所以他一旦被实例化就无法被修改。

    不可变类的实例一旦创建,其成员变量的值就不能被修改。这样设计有很多好处,比如可以缓存hashcode、使用更加便利以及更加安全等。

    但是,既然字符串是不可变的,那么字符串拼接又是怎么回事呢?

    其实,所有的所谓字符串拼接,都是重新生成了一个新的字符串


    2.
    运算符重载:在计算机程序设计中,运算符重载(英语:operator overloading)是多态的一种。
    运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。

    语法糖:语法糖(Syntactic sugar),也译为糖衣语法,是由英国计算机科学家彼得·兰丁发明的一个术语,
    指计算机语言中添加的某种语法,这种语法对语言的功能没有影响,但是更方便程序员使用。
    语法糖让程序更加简洁,有更高的可读性。

    3.使用+拼接字符串的实现原理

    使用+拼接字符串,其实只是Java提供的一个语法糖
    Java中的+对字符串的拼接,其实现原理是使用StringBuilder.append

    4.concat实现

    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对象并返回。


    5.StringBuffer和StringBuilder的实现原理

    StringBuilder类也封装了一个字符数组: char[] value;
    与String不同的是,它并不是final的,所以他是可以修改的。
    另外,与String不同,字符数组中不一定所有位置都已经被使用,
    它有一个实例变量,表示数组中已经使用的字符个数
    int count;

    append源码继承了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会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进行扩展。
    StringBuffer和StringBuilder类似,最大的区别就是StringBuffer是线程安全的

    StringBuffer的append方法:
    public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
    }
    该方法使用synchronized进行声明,说明是一个线程安全的方法

    6.StringUtils.join实现

    StringUtils.join的源代码:

    public static String join(final Object[] array, String separator, final int startIndex, final int endIndex) {
    if (array == null) {
    return null;
    }
    if (separator == null) {
    separator = EMPTY;
    }

    // endIndex - startIndex > 0: Len = NofStrings *(len(firstString) + len(separator))
    // (Assuming that all Strings are roughly equally long)
    final int noOfItems = endIndex - startIndex;
    if (noOfItems <= 0) {
    return EMPTY;
    }

    final StringBuilder buf = new StringBuilder(noOfItems * 16);

    for (int i = startIndex; i < endIndex; i++) {
    if (i > startIndex) {
    buf.append(separator);
    }
    if (array[i] != null) {
    buf.append(array[i]);
    }
    }
    return buf.toString();
    }

    也是通过StringBuilder来实现的。

    7.比较

    long t1 = System.currentTimeMillis();

    String str1 = "hello";
    String str2 = "world";
    StringBuilder str3 = new StringBuilder();
    StringBuffer str4 = new StringBuffer();
    for (int i = 0; i < 50000; i++) {
    //str1 = str1 + str2;//cost:5325
    //str1.concat(str2);//cost:5
    //str3.append(str2);//cost:2
    str4.append(str2);//cost:3

    }
    long t2 = System.currentTimeMillis();
    System.out.println("cost:" + (t2 - t1));

    StringBuilder<StringBuffer<concat<+<StringUtils.join


    8.结论

    直接使用StringBuilder的方式是效率最高的。因为StringBuilder天生就是设计来定义可变字符串和字符串的变化操作的。
    如果不是在循环体中进行字符串拼接的话,直接使用+就好了。

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

  • 相关阅读:
    opencvadd加法
    opencvcopyMakeBorder拓展边界
    opencvcountNonZero计算非0值个数
    opencvcompare比较
    opencvputText绘字
    opencvaddWeighted加法
    opencvconvertScaleAbs位深转化函数
    opencvsplit分离通道
    软件测试的人际关系(转载)
    Struts 1.3.10 jar包官网下载地址
  • 原文地址:https://www.cnblogs.com/wuxinyan/p/10297554.html
Copyright © 2011-2022 走看看