StringBuilder 插入使用 String.valueOf 是有原因的吗?

Is there a reason StringBuilder insert uses String.valueOf?

在 JDK 中,AbstractStringBuilder the append(int) 方法的实现方式是不分配不必要的内存(使用 Integer.getChars 直接写入内部 char[])。

但是 insert 的实现使用 String.valueOf 其中 returns 一个新字符串,然后将该数据复制到数组中。创建垃圾字符串。

StringBuilder 的要点之一不是减轻连接字符串的垃圾影响。 insert 的无垃圾实现似乎很容易实现。那为什么不呢?

Oracle JDK 和 OpenJDK 似乎都是这种情况。它甚至在 javadoc:

中被提及

The overall effect is exactly as if the second argument were converted to a string by the method String.valueOf(int), and the characters of that string were then inserted into this character sequence at the indicated offset.

如果将 insert(int,int) 与其他 insert 方法进行比较,您会发现实现方法是保持简单,通过让单个 insert(String) 方法减少代码重复完成所有实际工作。

这是软件开发中的合理方法,首先创建一个 straight-forward 处理所有情况的通用实现,然后对实际应用程序和场景进行分析以找到创建专门的地方,也许不是那么简单,优化版本有好处。似乎没有进行搜索以找到可以使用相同优化实现的其他地方。考虑到前面的测量显然没有将 insert(int,int) 显示为一个重要的热点,这并没有什么坏处。

要评估情况,重要的是要了解不是临时对象的数量导致重复 String.concat 昂贵。过度创建临时对象可能会火上浇油,因此如果有一个简单的选择,仍然值得避免。但是重复 String.concat 调用的问题是每个临时字符串实例的创建都意味着复制构成字符串内容的整个字符数据。 concat 调用字符串构建的次数越多,您就越接近二次时间复杂度。

StringBuilder 通过使用可变缓冲区解决了这个问题。当容量耗尽时它仍然被复制,但是通过使用一个因子来确定新的容量,整体时间复杂度保持线性。 insert 的实现并没有改变这个基本原则。临时 String 实例只会导致 right-hand 端的复制,因此它只会引入常数因子二,而不是改变时间复杂度。

但不要忘记insert原则上承载了缓冲区后续字符数据的副本。如果您在缓冲区的开头重复插入,您将转向二次时间复杂度,无论底层实现的优化程度如何。因此,如果您过度这样做,无论如何,2 的因数将变得可以忽略不计。