在String字符串拼接性能优化 博客中我已经介绍过了String "+" 拼接背后的StringBuilder实现。也聊到了StringJoiner、Joiner等类库都是通过StringBuilder实现的拼接。
那么今天我们来聊一聊StringBuilder还有什么点比较好玩。
StringBuilder的使用上,应该来说性能问题取决于扩容操作是否频繁,还有char数组是否浪费,所以一般来说大家都听过要预估一个StringBuilder的容量去构造。那除此之外,StringBuilder还有哪些空间可以让我们搞一些优化呢?
在介绍优化方式之前,需要一点基础知识,我们看一段代码
如上,在StringBuilder对象重新设置length属性之后,之前append的值没有了。
然后我charAt发现char[]第一位变成了4,且不允许访问第二位。
然后我们来看一下几个方法的源码
如上,我们可以知道StringBuilder底层是一个char数组,然后count代表的是append char字节的次数,注意这里不是append的次数,而是string拆成了char之后的length。
然后toString就是操作一个new String(char[],0,count),跟JSON toJSONString那块源码一样。
那么setLength其实就是重新赋值了count值,然后append操作又是从数组0位操作的。
所以在setLength为0之后,再append值,char[]就会从0位开始替换原来的值,可以debug验证一下。
如上图,append("1","2","3")之后setLength为0,之后append("4"),就会变成4,2,3组成的char[]。
最后输出toString自然只会偏移count值的char出来,那么就只会输出4,而char[]复用了。
说到这里,是不是已经有灵感了?
没错,我们对StringBuilder优化的思路就在于复用char[]。
那么第一版我们能想到的方案就是一个静态单例工具类做法,如下:
这样我就可以不用创建多个StringBuilder,只需要reset就能复用char[]且忽略之前append的值,这会让我们节省char[]创建和扩容的时间&空间成本。
这个版本基本上够用了,但是线程不安全,那么线程安全版本的如下:
这个版本最初的实现在哪里呢?BigDecimal源码、Netty源码
所以没事看看jdk源码还是很重要的~