字符串拼接五种常⽤⽅法
字符串,是Java中最常⽤的⼀个数据类型了。本⽂,也是对于Java中字符串相关知识的⼀个补充,主要来介绍⼀下字符串拼接相关的知识。本⽂基于jdk1.8.0_181。字符串拼接是我们在Java代码中⽐较经常要做的事情,就是把多个字符串拼接到⼀起。我们都知道,String是Java中⼀个不可变的类,所以他⼀旦被实例化就⽆法被修改。(不可变类的实例⼀旦创建,其成员变量的值就不能被修改。这样设计有很多好处,⽐如可以缓存hashcode、使⽤更加便利以及更加安全等)。
但是,既然字符串是不可变的,那么字符串拼接⼜是怎么回事呢?字符串不变性与字符串拼接,其实,所有的所谓字符串拼接,都是重新⽣成了⼀个新的字符串。下⾯⼀段字符串拼接代码:
String s = "abcd";
s = s.concat("ef");
其实最后我们得到的s已经是⼀个新的字符串了。如下图:
中保存的是⼀个重新创建出来的String对象的引⽤。那么,在Java中,到底如何进⾏字符串拼接呢?字符串拼接有很多种⽅式,这⾥简单介绍⼏种⽐较常⽤的。
⼀,使⽤+拼接字符串
在Java中,拼接字符串最简单的⽅式就是直接使⽤符号+来拼接。如:
String wechat = "Hollis";
String introduce = "召唤师峡⾕";
String hollis = wechat + "," + introduce;
这⾥要特别说明⼀点,有⼈把Java中使⽤+拼接字符串的功能理解为运算符重载。其实并不是,Java是不⽀持运算符重载的。这其实只是Java提供的⼀个语法糖。后⾯再详细介绍。
概念普及:
运算符重载:在计算机程序设计中,运算符重载(英语:operator overloading)是多态的⼀种。运算符重载,就是对已有的运算符重新进⾏定义,赋予其另⼀种功能,以适应不同的数据类型。
语法糖:语法糖(Syntactic sugar),也译为糖⾐语法,是由英国计算机科学家彼得·兰丁发明的⼀个术语,指计算机语⾔中添加的某种语法,这种语法对语⾔的功能没有影响,但是更⽅便程序员使⽤。语法糖让程序更加简洁,有更⾼的可读性。
concat
除了使⽤+拼接字符串之外,还可以使⽤String类中的⽅法concat⽅法来拼接字符串。如:
String wechat = "Hollis";
String introduce = "召唤师峡⾕";
String hollis = at(",").concat(introduce);
StringBuffer
关于字符串,Java中除了定义了⼀个可以⽤来定义字符串常量的String类以外,还提供了可以⽤来定义字符串变量的StringBuffer 类,它的对象是可以扩充和修改的。使⽤StringBuffer可以⽅便的对字符串进⾏拼接。如:
StringBuffer wechat = new StringBuffer("Hollis");
String introduce = "召唤师峡⾕";
StringBuffer hollis = wechat.append(",").append(introduce);
StringBuilder
除了StringBuffer以外,还有⼀个类StringBuilder也可以使⽤,其⽤法和StringBuffer类似。如:
StringBuilder wechat = new StringBuilder("Hollis");
String introduce = "召唤师峡⾕";
StringBuilder hollis = wechat.append(",").append(introduce);
StringUtils.join
除了JDK中内置的字符串拼接⽅法,还可以使⽤⼀些开源类库中提供的字符串拼接⽅法名,如apachemons中提供的StringUtils类,其中的join⽅法可以拼接字符串。
String wechat = "Hollis"; String introduce = "召唤师峡⾕";
System.out.println(StringUtils.join(wechat, ",", introduce));
这⾥简单说⼀下,StringUtils中提供的join⽅法,最主要的功能是:将数组或集合以某拼接符拼接到⼀起形成新的字符串,如:
String []list ={"Hollis","每⽇更新Java相关技术⽂章"};
String result= StringUtils.join(list,",");
System.out.println(result); //结果:Hollis,每⽇更新Java相关技术⽂章
并且,Java8中的String类中也提供了⼀个静态的join⽅法,⽤法和StringUtils.join类似。
以上就是⽐较常⽤的五种在Java种拼接字符串的⽅式,那么到底哪种更好⽤呢?为什么阿⾥巴巴Java开
发⼿册中不建议在循环体中使⽤+进⾏字符串拼接呢?
接下来我们就来分析⼀下以上五种⽅式的底层原理,再来分析到底哪种更好。
使⽤+拼接字符串的实现原理:
前⾯提到过,使⽤+拼接字符串,其实只是Java提供的⼀个语法糖,那么,我们就来解⼀解这个语法糖,看看他的内部原理到底是如何实现的。还是这样⼀段代码。我们把他⽣成的字节码进⾏反编译,看看结果。
String wechat = "Hollis";
String introduce = "每⽇更新Java相关技术⽂章";
String hollis = wechat + "," + introduce;
反编译后的内容如下,反编译⼯具为jad。
String wechat = "Hollis"; String introduce = "每⽇更新Java相关技术⽂章";
String hollis = (new StringBuilder()).append(wechat).append(",").append(introduce).toString();
通过查看反编译以后的代码,我们可以发现,原来字符串常量在拼接过程中,是将String转成了StringBuilder后,使⽤其
append⽅法进⾏处理的。
那么也就是说,Java中的+对字符串的拼接,其实现原理是使⽤StringBuilder.append。
concat是如何实现的
我们再来看⼀下concat⽅法的源代码,看⼀下这个⽅法⼜是如何实现的。
public String concat(String str) {
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length; char buf[] = pyOf(value, len + otherLen);
}
这段代码⾸先创建了⼀个字符数组,长度是已有字符串和待拼接字符串的长度之和,再把两个字符串的值复制到新的字符数组中,并使⽤这个字符数组创建⼀个新的String对象并返回。通过源码我们也可以看到,经过concat⽅法,其实是new了⼀个新的String,这也就呼应到前⾯我们说的字符串的不变性问题上了。
StringBuffer和StringBuilder
接下来我们看看StringBuffer和StringBuilder的实现原理。
和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);
}
append会直接拷贝字符到内部的字符数组中,如果字符数组长度不够,会进⾏扩展。
StringBuffer和StringBuilder类似,最⼤的区别就是StringBuffer是线程安全的,看⼀下StringBuffer的append⽅法。
public synchronized StringBuffer append(String str) {
toStringCache = null;
  super.append(str);
  return this;
}
该⽅法使⽤synchronized进⾏声明,说明是⼀个线程安全的⽅法。⽽StringBuilder则不是线程安全的。
StringUtils.join是如何实现的:
通过查看StringUtils.join的源代码,我们可以发现,其实他也是通过StringBuilder来实现的。
1. public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
1. public static String join(final double[] array, final char separator, final int startIndex, final int endIndex) {
2.            if (array == null) {
java中字符串转数组3.                return null;
4.
5.            }
6.
7.      final int noOfItems = endIndex - startIndex;
8.
9.          if (noOfItems <= 0) {
10.
11.                return EMPTY;
12.
13.          }
14.
15.          final StringBuilder buf = new StringBuilder(noOfItems * 16);
16.
17.          for (int i = startIndex; i < endIndex; i++) {
18.
19.                  if (i > startIndex) {
20.
21.                        buf.append(separator);
22.
23.                  }
24.
25.                  buf.append(array[i]);
26.
27.          }
28.
29.        String();
30.
31. }
效率⽐较:
从结果可以看出,⽤时从短到长的对⽐是:StringBuilder < StringBuffer < concat < + < StringUtils.join
所以,阿⾥巴巴Java开发⼿册建议:循环体内,字符串的连接⽅式,使⽤ StringBuilder 的 append ⽅法进⾏扩展。⽽不要使⽤+。
总结
本⽂介绍了什么是字符串拼接,虽然字符串是不可变的,但是还是可以通过新建字符串的⽅式来进⾏字符串的拼接。
常⽤的字符串拼接⽅式有五种,分别是使⽤+、使⽤concat、使⽤StringBuilder、使⽤StringBuffer以及使⽤StringUtils.join。
由于字符串拼接过程中会创建新的对象,所以如果要在⼀个循环体中进⾏字符串拼接,就要考虑内存问题和效率问题。
因此,经过对⽐,我们发现,直接使⽤StringBuilder的⽅式是效率最⾼的。因为StringBuilder天⽣就是设计来定义可变字符串和字符串的变化操作的。
但是,还要强调的是:
1、如果不是在循环体中进⾏字符串拼接的话,直接使⽤+就好了。
2、如果在并发场景中进⾏字符串拼接的话,要使⽤StringBuffer来代替StringBuilder。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。