将以下代码作为样本:
Map<String, List<String>> warningMap = (Map<String, List<String>>) warningsOrErrorsMapVariable;
StringBuilder warningMessages = new StringBuilder(size?!);
for (Iterator<String> keyIterator = warningMap.keySet().iterator(); keyIterator.hasNext();) {
Object key = keyIterator.next();
if (!keyIterator.hasNext()) {
isLastKey = true;
}
List<String> values = warningMap.get(key);
if (values != null) {
isLastValue = false;
for (Iterator<String> valueIterator = values.iterator(); valueIterator.hasNext();) {
String message = valueIterator.next();
if (!valueIterator.hasNext()) {
isLastValue = true;
}
warningMessages.append(message);
if (!(isLastKey && isLastValue)) {
warningMessages.append(NEW_LINE);
}
}
}
}
return warningMessages.toString();
为复合结构声明StringBuiler
适当大小的最佳做法是什么?
其中一个选项是通过mapElems* listElems * predictedListElemSize
预测整个地图的大小,另一个选项是访问每个元素并获得精确的大小,但是它们都需要通过所有地图迭代两次 - 首先是获取大小,其次是获取字符串值附加到缓冲区。这值得么?
不是整个&#34;计算尺寸的元素&#34;比需要时调整构建器缓冲区更耗时吗?
答案 0 :(得分:3)
听起来像是对我不成熟的优化。在大多数情况下,默认大小实际上不是最佳选择(很少使用StringBuilder
表示短于16个字符的字符串),所以做一个简单的假设。
除非这里确实存在性能问题,否则增加计算或多或少准确缓冲区大小的复杂性并不会带来回报。只需稍微大一点的缓冲区256或1024字节就可以了,忘了它。
在您的代码中,我宁愿专注于Map
上的低效循环:您正在迭代keySet()
并使用Map.get()
在几乎每次迭代中获取值。从头开始使用entrySet()
进行迭代!
答案 1 :(得分:1)
除非你有一个非常好的理由来确保StringBuilder的大小正确,否则最好的做法是使用默认大小,并让StringBuilder按需增长。
我能想到的唯一“非常好”的理由(在我的头脑中)是:
您的程序在严格的内存限制下运行,如果StringBuilder需要扩展,则内存不足,或者
您已经分析了您的应用程序,扩展StringBuilder所带来的额外工作是一个关键的性能瓶颈。
否则,尝试调整大小是不必要的优化。
我相信您希望我在您编辑过的问题中注明这句话。
整个“elems的计算大小”是否比在需要时调整构建器的缓冲区更耗时?
可能是也可能不是。 (我倾向于不在你的例子中思考,因为String.length()
便宜且O(1)
。)但我想说的是,你甚至不应该思考关于这个,除非你有明确的证据表明优化(以及额外的代码复杂性)是非常必要的。
答案 2 :(得分:1)
是的,将地图的大小乘以预期(估计)平均列表大小和预期(估计)平均字符串长度应该足够了。
StringBuilder的增长算法不是线性的:它每次都会翻倍,所以通过精确估计其最终大小,你不会获得太多收益。
我怀疑这是你遇到任何性能问题的地方。
旁注:如果您在除第一个元素之外的每个元素之前添加换行符,并使用foreach循环语法,则代码会更容易。您还应该遍历地图的entrySet()
,而不是遍历键并在每次迭代时进行查找:
boolean isFirst = true;
for (Map.Entry<String, List<String>> entry : warningMap.entrySet()) {
List<String> warnings = entry.getValue();
if (warnings != null) {
for (String warning : warnings) {
if (!isFirst) {
warningMessages.append(NEW_LINE);
}
isFirst = false;
warningMessages.append(warning);
}
}
}