Several ways and the difference between string concatenation

String, Java is the most commonly used type of data.

This article is also a supplement for Java string related knowledge, mainly to introduce the relevant knowledge of string concatenation. This article jdk1.8.0_181 based.

String concatenation

We compare the string concatenation is often done in Java code thing, it is to splice multiple strings together.

As we all know, String is an immutable Java class is instantiated once so he can not be modified.

Examples immutable once created class, member variables whose values ​​can not be modified. This design has many advantages, such as can be cached hashcode, more convenient to use and more security.

However, since strings are immutable, the string concatenation is how it happened?

String invariance and string concatenation

In fact, all of the so-called string concatenation, are regenerate a new string. Code strings together the following paragraph:

String s = "abcd";
s = s.concat("ef");

In fact, the last we get s already a new string of. As shown below

S reference is stored in a re-created out of the String object.

So, in Java, in the end how the string concatenation it? String concatenation There are many ways, here a brief introduction of several commonly used.

Using +string concatenation

In Java, the string concatenation easiest way is to directly use the symbol +to splice. Such as:

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

Here we must point out, some people in Java using +string concatenation function understood as operator overloading. Not really, Java does not support operator overloading. This is really just a syntactic sugar provided by Java. Later re-introduced in detail.

Operator overloading: In computer programming, the operator overloading (English: operator overloading) is a polymorphism. Operator overloading, the existing operator is redefined, giving it another function, to accommodate different data types.

Syntactic sugar: syntactic sugar (Syntactic sugar), also translated as icing grammar, terminology is a British computer scientist Peter Landin invention, refers to some kind of computer language syntax added, this syntax has no effect on the function of language, but programmers to use more convenient. Syntactic sugar to make the program more compact, higher readability.

concat
except +splicing string, a method may also be used a method concat class String to string concatenation. Such as:

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

StringBuffer

On the string, Java defines, in addition to a string constants can be used to define the Stringclass, it also can be provided to define the string variable StringBufferclass, its object can be expanded and modified.

Use StringBuffercan easily splice the string. Such as:

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

StringBuilder
addition to StringBufferoutside, there is a class StringBuildermay also be used, its usage and StringBufferthe like. Such as:

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

StringUtils.join
addition to the built-in string concatenation method JDK may also use some method of splicing name string open source library provided, such as apache.commons中provided by the StringUtilsclass, wherein the joinmethod may string concatenation.

String wechat = "Hollis";
String introduce = "每日更新Java相关技术文章";
System.out.println(StringUtils.join(wechat, ",", introduce));

Here briefly about, join StringUtils method provided, the main functions are: to set the array or a mosaic character spliced ​​together to form a new string, such as:

String []list  ={"Hollis","每日更新Java相关技术文章"};
String result= StringUtils.join(list,",");
System.out.println(result);
//结果:Hollis,每日更新Java相关技术文章

And, in Java8 String class also provides a static join method, usage and StringUtils.join similar.

These are the more commonly used five ways to concatenate strings in Java, then in the end which is better to use it? Why Alibaba Java Developer's Handbook is not recommended for use in the body of the loop +string stitching it?

(Statute on string concatenation of Alibaba Java Developer's Handbook)

Use +realization of the principle of string concatenation

As we mentioned earlier, using +string concatenation, in fact, just a syntactic sugar provided by Java, then we have a solution to solve this syntactic sugar to see if his internal principle in the end is how to achieve.

Or this piece of code. We took him to generate bytecode decompile, look at the results.

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

反编译后的内容如下,反编译工具为jad。

String wechat = "Hollis";
String introduce = "\u6BCF\u65E5\u66F4\u65B0Java\u76F8\u5173\u6280\u672F\u6587\u7AE0";//每日更新Java相关技术文章
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();

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

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

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

通过源码我们也可以看到,经过concat方法,其实是new了一个新的String,这也就呼应到前面我们说的字符串的不变性问题上了。

StringBuffer和StringBuilder

接下来我们看看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则不是线程安全的。

StringUtils.join是如何实现的

通过查看StringUtils.join的源代码,我们可以发现,其实他也是通过StringBuilder来实现的。

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

效率比较

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

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
StringUtils.join cost:25726

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

StringBuilder<StringBuffer<concat<+<StringUtils.join

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

StringUtils.join也是使用了StringBuilder,并且其中还是有很多其他操作,所以耗时较长,这个也容易理解。其实StringUtils.join更擅长处理字符串数组或者列表的拼接。

那么问题来了,前面我们分析过,其实使用+拼接字符串的实现原理也是使用的StringBuilder,那为什么结果相差这么多,高达1000多倍呢?

我们再把以下代码反编译下:

long t1 = System.currentTimeMillis();
String str = "hollis";
for (int i = 0; i < 50000; i++) {
    String s = String.valueOf(i);
    str += s;
}
long t2 = System.currentTimeMillis();
System.out.println("+ cost:" + (t2 - t1));

反编译后代码如下:

long t1 = System.currentTimeMillis();
String str = "hollis";
for(int i = 0; i < 50000; i++)
{
    String s = String.valueOf(i);
    str = (new StringBuilder()).append(str).append(s).toString();
}

long t2 = System.currentTimeMillis();
System.out.println((new StringBuilder()).append("+ cost:").append(t2 - t1).toString());

我们可以看到,反编译后的代码,在for循环中,每次都是new了一个StringBuilder,然后再把String转成StringBuilder,再进行append

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

所以,阿里巴巴Java开发手册建议:循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。而不要使用+

总结

本文介绍了什么是字符串拼接,虽然字符串是不可变的,但是还是可以通过新建字符串的方式来进行字符串的拼接。

常用的字符串拼接方式有五种,分别是使用+、使用concat、使用StringBuilder、使用StringBuffer以及使用StringUtils.join

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

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

但是,还要强调的是:

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

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

Guess you like

Origin www.cnblogs.com/lujiahua/p/11408689.html