写点什么

为什么阿里巴巴不建议在 for 循环中使用”+,java 编程技术开发题库和答案

用户头像
极客good
关注
发布于: 刚刚

System.out.println(StringUtils.join(wechat, ",", introdu


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


ce));


这里简单说一下,StringUtils 中提供的 join 方法,最主要的功能是:将数组或集合以某拼接符拼接到一起形成新的字符串,如:


String []list ={"Hollis","每日更新 Java 相关技术文章"};


String result= StringUtils.join(list,",");


System.out.println(result);


//结果:Hollis,每日更新 Java 相关技术文章


并且,Java8 中的 String 类中也提供了一个静态的 join 方法,用法和 StringUtils.join 类似。


以上就是比较常用的五种在 Java 种拼接字符串的方式,那么到底哪种更好用呢?为什么阿里巴巴 Java 开发手册中不建议在循环体中使用+进行字符串拼接呢?


还是这样一段代码。我们把他生成的字节码进行反编译,看看结果。


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


二、原理篇



1、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,这也就呼应到前面我们说的字符串的不变性问题上了。

2、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则不是线程安全的。

3、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++) {

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
为什么阿里巴巴不建议在for循环中使用”+,java编程技术开发题库和答案