注意:本问题涉及 Java >= 9 引入的"紧凑字符串"。
假设我正在向一个 StringBuilder 中追加未知数量的字符串(或字符),并在某个时刻确定我正在追加最后一个字符串。如何高效地完成这项任务?
背景:如果字符串构建器的容量不够大,它将始终将其增加到 max(oldCap + str.lenght(), oldCap * 2 + 2)。因此,如果您运气不佳,容量不足以容纳最后一个字符串,它将不必要地使容量翻倍,例如:
唯一的缺点是,如果现有的字符串生成器或新字符串不是Latin 1(每个字符2字节),那么新创建的字符串生成器必须从每个字符1字节(Latin 1)“膨胀”到每个字符2字节。
假设我正在向一个 StringBuilder 中追加未知数量的字符串(或字符),并在某个时刻确定我正在追加最后一个字符串。如何高效地完成这项任务?
背景:如果字符串构建器的容量不够大,它将始终将其增加到 max(oldCap + str.lenght(), oldCap * 2 + 2)。因此,如果您运气不佳,容量不足以容纳最后一个字符串,它将不必要地使容量翻倍,例如:
StringBuilder sb = new StringBuilder(4000);
sb.append("aaa..."); // 4000 * "a"
// Last string:
sb.append("b"); // Unnecessarily increases capacity from 4000 to 8002
return sb.toString();
StringBuilder
提供了capacity()
、length()
和getChars(...)
方法,但是手动创建一个char[]
,然后创建一个字符串将会效率低下,因为:
- 由于“紧凑字符串”,字符串生成器必须将其字节转换为字符
- 调用其中一个
String
构造函数时,字符必须再次被压缩为字节
另一种选择是检查capacity()
,如果需要则创建一个new StringBuilder(sb.length() + str.length())
,然后附加sb
和str
:
StringBuilder sb = new StringBuilder(4000);
sb.append("aaa..."); // 4000 * "a"
String str = "b";
if (sb.capacity() - sb.length() < str.length()) {
return new StringBuilder(sb.length() + str.length())
.append(sb)
.append(str)
.toString();
}
else {
return sb.append(str).toString();
}
唯一的缺点是,如果现有的字符串生成器或新字符串不是Latin 1(每个字符2字节),那么新创建的字符串生成器必须从每个字符1字节(Latin 1)“膨胀”到每个字符2字节。
return sb.toString() + str;
(请参见“今天的教训”此处(通过此文章)). 我不认识这些专家,所以您可能需要调查他们的可信度。 - vanOekelchar[]
,但将它们转换为字符串,然后使用字符串连接可能仍然更有效率。 - Marcono1234StringBuilder
,但五种策略中有四种仍然在幕后使用它。 - EugeneStringBuilder
更加高效。更多信息 - Eugenereturn sb + str;
而不强制创建另一个中间的String
实例。 - Holger