StringBuilder是平常编程中比较常用的JDK下的类之一。在字符串的拼接中发挥着重大的作用。可能很多人对于StringBuilder的认识并不深刻。这里通过我的理解来阐述一下StringBuilder。
1.为什么要使用StringBuilder?
这里很多人可能会说有“+”写出来的代码可能不是那么雅观,可能算做一个,另外更重要的原因是众所周知的性能。这在很多面试题里会屡试不爽的提在字符串拼接的情况下使用StringBuilder,在for循环下更是如此。why?这里归根结底是String的final特性决定的。如果细心的同学可以看一下String的源码中存储的数组就是final类型的。String本身是无法达到扩容的目的。
2.为什么StringBuilder可以得到性能上的提升。
StringBuilder内部也是一个char数组,这和String内部的存储实现无异。下面用具体的代码来看一下使用String和StringBuilder在性能上的差异和性能到底损失在什么地方。
@Test
public void test3(){
String s = null;
for(int i=0;i<1000;i++){
s +=i;
}
}
@Test
public void test4(){
StringBuilder builder = new StringBuilder();
for(int i=0;i<1000;i++){
builder.append(i);
}
}
@Test
public void test5(){
StringBuilder builder = new StringBuilder(3000);
for(int i=0;i<1000;i++){
builder.append(i);
}
}
test3方法
采用最笨的+操作符,上面已经说String是final类型的,可以看一下中间会产生出多少中间对象,可以简单的算一下,本身循环1000次会有1000个对象,另外实现+操作后又产生1000个对象。最后垃圾回收多少对象?回收1999个对象。只保留最后一个s对象。
test4方法
采用不初始化初始容器的方式进行,这也是大部分程序员能做到的。这里会产生多少对象呢?在外面看来是1001个对象,其实不是这样的。这里又要看一下StringBuilder的初始容量是16。当i=13的时候出现了一次扩容,看一下内部的会用到System.arrayCopy来实现一个扩容机制。这里再回到StringBuilder内部的存储是采用char数组实现存储的,而这个char[]的初始容量就是16,这样当i=13的时候会发现原来的数组已经装不下了,这时候怎么办?这时候首先申请一个更大容量的数组,新申请数组的大小是多少呢?是(当前容量的大小+1)*2,也就是34,很多人说我这时候加入的字符串还是大于扩充的容量怎么办,这里做一个处理,就是如果发现加进来的字符串的大小大于当前新申请的容量,就以新加进来的字符串的大小作为申请容易的大小。这里说的有点绕,看代码会清晰很多。
回到我所说的test4例子,根据上面的分析,其实StringBuilder需要做几次扩容才能完成,这里性能损失会在哪,一个是数组copy,另外一个就是扩容产生的垃圾对象需要JVM回收都会造成性能损耗。算一下这里要扩容几次。要扩容8次,中间就会产生8个中间对象需要JVM回收,而越往后面垃圾对象越大。
test5方法
test5在test4上面的改进主要就是初始化容量,这么做的好处就是省去了8次扩容产生的性能损耗和JVM回收垃圾的时间。
结论
所以在知道当前你append字符串容量的情况下可以指定其大小,在某些场景下有不少的性能提升。上面的分析同样可以平移到ArrayList,HashMap等内部采用数组实现的结构中。
3.如何计算需要初始化容量的大小?
String类型好算一些,length就可以了。像一些int类型,long类型它们需要申请多少空间呢?举一个简单的例子,像int类型的1000在StringBuilder需要占几个?答案是4个,如果去看一下源码就知道,它其实是转成String存,当然内部并没有强转成String,而是用了getChars方法。里面用了一些小技巧来获得一些性能的提升,有兴趣的同学也可以去看一下StringBuilder的实现。
4.具体的性能有多大的提升?
这里有兴趣的同学可以去压测一下。
分享到:
相关推荐
StringBuffer & StringBuilder 源码分析.docx
String StringBuffer和StringBuilder 区别之源码解析 从源码角度简单对它们之间的区别进行了验证
主要针对Java中两个常用的操作字符串的类 StringBuilder和StringBuffer进行源码分析,感兴趣的小伙伴们可以参考一下
主要给大家介绍了关于JDK源码分析之String、StringBuilder和StringBuffer的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用jdk具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
主要介绍了JAVA面试题 从源码角度分析StringBuffer和StringBuilder的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,下面我们来一起学习下吧
JDK1.8源码分析 导入源码过程中的注意事项 JDK1.8对应JDK版本下载: 提取码:49wi 源码在src目录下 以下两个类手动添加的,解决编译过程中该包的丢失 sun.font.FontConfigManager sun.awt.UNIXToolkit 其中: 1.请...
集合源码分析 JAVA: 基本语法 static 修饰变量 方法 静态块(初始化块 构造函数 ) 静态内部类() 静态导包 final() transient() foreach循环原理() volatile底层实现() equals和hashcode(, ) string,stringbuffer和...
文章目录一、前言二、值可变性三、线程安全性四、时间性能排名 一、前言 此博客基于JDK1.8。 我们先用一张表格来回顾一下Java中String,StringBuilder,StringBuffer...接着我们由源码可以看到,Java中String类,Stri
jdk1.8-source-analysis JDK1.8源码分析引入原始过程中的注意事项JDK1.8对应JDK版本下载: 码:49wi原始码在src目录下以下两个类手动添加的,解决编译过程中该包的丢失sun.font.FontConfigManager sun.awt....
JDK1.8源码分析 引入原始过程中的注意事项 JDK1.8对应JDK版本下载: 码:49wi 原始码在src目录下 以下两个类手动添加的,解决编译过程中该包的丢失 sun.font.FontConfigManager sun.awt.UNIXToolkit 其中:1.请...
8.7 String对象、StringBuilder对象和原始数据类型的特点 116 8.7.1 String对象的“equals()”和“==” 116 8.7.2 StringBuilder对象 116 8.7.3 原始数据类型的“==” 117 8.8 代码双击域onchange之后弹出iframe窗口...
JDK1.8源码分析 导入源码过程中的注意事项 源码在%JAVA_HOME%\src.zip 源码在src目录下 以下两个类手动添加的,解决编译过程中该包的丢失 sun.font.FontConfigManager sun.awt.UNIXToolkit 其中: 1.请手动添加jdk...
本文的写作冲动来源于今晚看到的老赵的一则微博“大家知道System.Collections.Generic.List是一种什么样的数据结构?内部的元素是怎么存放的?还有Dictionary呢?…”。 查了一下书,如果参考数据结构和算法里介绍的...
jdk1.8-source-analysis JDK1.8源码分析引入原始过程中的注意事项JDK1.8对应JDK版本下载: 码:49wi原始码在src目录下以下两个类手动添加的,解决编译过程中该包的丢失sun.font.FontConfigManager sun.awt....
该源码资源适用于任何需要对字符串进行处理的场景,包括但不限于文本分析、数据清洗、字符串匹配和替换等。无论是在后端开发还是前端开发中,都可以利用这个源码资源来简化字符串操作的过程。 目标 该源码资源的...
java设计模式【之】建造者模式【源码】【场景:车辆组装】 将复杂的对象构建,与对象的使用进行分离 用户只需要通过简单流程即可创建出对象 方法调用顺序,步骤的不同实现 优点:封装性号,创建和使用分离,扩展性...
*****是随书源码光盘***** *****人民邮电出版社***** **长春明日科技组织编写** 本书从初学者角度出发,通过通俗易懂的语言和大量生动典型的实例,由浅入深、循序渐进地介绍使用C#进行WinForms程序开发的常用技术和...
对于程序本身的优化,可以借鉴很多前辈的经验,但是有些时候,在从源码角度分析的话,不好鉴别出哪个效率高,如对字符串拼接的操作,是直接“+”号拼接效率高还是使用StringBuilder效率高呢? 这个时候,就需要通过...
9.3 StringBuilder类的使用233 9.4 日期类简介234 9.5 Java语言国际化时间获取与计算238 9.6 Random类和Math类240 9.7 本章习题243 第10章 10.1 异常概述246 10.2 使用try和catch捕获异常..2 50 10.3 使用throw和...
String,StringBuffer,StringBuilder的区别,多线程下的优缺点,从源代码分析 对象的三大特性 接口和抽象类的区别,使用场景 类的实例化顺序,当new执行的时候,父类静态数据,父类构造函数,字段,子类静态数据,...