猿问

初始化 StringBuilder 以使用 UTF-16 编码器

考虑 Java 11 中的以下代码:

StringBuilder sb = new StringBuilder("one");
sb.append("δύο");  // "two"

第一行创建一个StringBuilder使用 Latin1 编码器的代码(每个字符一个字节)。然后第二行使 StringBuilder 意识到它需要改用 UTF16 编码器,因此它在附加新的 UTF-16 字符之前将其当前内容复制到一个新数组中。

StringBuilder 类有一个构造函数重载,它接受一个初始容量参数,如果您已经知道要构建的字符串的所需大小,它旨在避免重新分配。但是如果你从一个英文字符串开始,然后附加一个外国字符串,这个特殊的构造函数重载就没有用了,因为它仍然重新分配字节数组。

有没有办法创建一个从一开始就使用 UTF16 的 StringBuilder 实例?


慕桂英3389331
浏览 122回答 3
3回答

catspeake

Java 11 或 Java 12 版本中没有任何东西StringBuilder可以做到这一点。真正的问题是您可能从中获得的性能提升对您有多重要。 分析您的应用程序以了解这种不需要的重新分配是否对您的应用程序的整体性能有显着影响。如果它要产生重大影响,您可以实现自己的版本StringBuilder(扩展相同的接口以实现兼容性)。或者,如果您准备等待,您可以下载 OpenJDK 源代码并开发/构建/测试扩展以StringBuilder……并将其作为补丁提交以供考虑。(如果您包含了显示出明显性能优势的基准,那将有助于增加包含的机会。)

素胚勾勒不出你

对此做了更多研究后,我为我自己的问题提供了另一个答案(Stack Overflow 说回答你自己的问题是完全可以接受的。)正如Slawomir 所说,无论如何,StringBuilder 都会使用 Latin1 进行初始化。因此,假设您主要使用俄语、中文、印地语或希腊语等语言写作。您想要构建一个已知其最大大小的字符串,因此您使用初始容量参数:StringBuilder sb = new StringBuilder(4096); sb.append("Здравствуйте!");  // Should easily fit in 4 kilobytes, right?然而,上面的调用append会丢弃您之前初始化的 4KB 缓冲区并分配一个新缓冲区。您构造了具有初始容量的 StringBuilder 以避免重新分配缓冲区,但 StringBuilder 无论如何都重新分配了它。它重新分配了它,即使它已经足够大了!解决方法是使用 JVM 选项运行 java -XX:-CompactStrings。如果您始终使用其中一种语言,那么您的字符串无论如何都会使用 UTF-16,因此在启动时关闭字符串压缩将减少检查您提供的每个字符串以查看它是否可以使用 Latin1 编码存储的开销。另请参阅Heinz Kabutz 于 2019 年 5 月 29 日在保加利亚 jPrime 上的演讲,其中他导致 StringBuilder 由于此“功能”而耗尽内存。

青春有我

似乎没有明显的。如果您想影响 StringBuffer 初始化的方式,我的建议是创建一个实用程序“初始化器”来实现CharSequence和使用相应的 StringBuilder 构造函数。您可以使用它来传达任何长度和字符内容,并且 StringBuilder 内部应该足够聪明以接受它。不过,看看 OpenJDK 11 的实现,它似乎无论如何都要从 Latin1 开始。某种形式的重新分配似乎总是会发生。
随时随地看视频慕课网APP

相关分类

Java
我要回答