对于最多 9-10 步的字符串连接,是否有比 StringBuilder 更快的方法?
我有这段代码来连接一些数组元素:
StringBuilder sb = new StringBuilder();
private RatedMessage joinMessage(int step, boolean isresult) {
sb.delete(0, sb.length());
RatedMessage rm;
for (int i = 0; i <= step; i++) {
if (mStack[i] == null)
continue;
rm = mStack[i].getCurrentMsg();// msg is built upfront, this just returns, it's a getter method call
if (rm == null || rm.msg.length() == 0)
continue;
if (sb.length() != 0) {
sb.append(", ");
}
sb.append(rm.msg);
}
rm.msg=sb.toString();
return rm;
}
重要的是,数组最多可容纳 10 个项目,因此数量并不多。
我的跟踪输出告诉我这个方法被调用了 18864 次,16% 的运行时间花费在这个方法上。我可以进一步优化吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
首先,我不会重用 StringBuilder 并始终创建新实例。这肯定会更快,因为它允许 GC 使用年轻代堆区域。
允许消除至少一个 if 语句的另一个小技巧是重写代码,如下所示:
First of all I won't reuse StringBuilder and always create new instance. That will be certainly faster, because it would allow GC to use young generation heap area.
Another little trick that allows to eliminate at least one if statement is to rewrite your code like this:
一些想法:
1)您是否使用估计的最大容量初始化 StringBuilder ?这样可以节省内部数组重新分配&所花费的时间。复制。
2)也许您可以在循环中附加一个尾随逗号,并避免循环内字符串长度的条件。相反,请在方法末尾添加一个条件,并根据需要删除结尾的逗号。
some ideas:
1) Do you initialize the StringBuilder with the estimated max capacity? This can save the time spent in the inner array re-allocation & copying.
2) Maybe you can append a trailing comma in the loop, and avoid the condition for string length inside the loop. Instead, add a single condition at the end of the method, and remove the trailing comma if needed.
您可以进行以下更改(仅显示差异):
它会消除 9 次额外的 if,但代价是添加一次空字符串。在决定保留此更改之前,您应该衡量它是否对您正在使用的数据有帮助:-)
You can make the following change (showing only the differences):
It gets rid if an extra if 9 times at the cost of adding an empty string once. You should measure if it helps at all with the data you are using before you decide to keep this change :-)
如果你的函数应该连接数组元素,为什么你要传递所有这些疯狂的值和未使用的参数?
If your function is supposed to concatenate array elements, why are you passing in all these crazy values and unused parameters?
首先遍历堆栈中的每个元素,计算所有字符串长度的总和。
然后,您可以使用
字符串构建器,就像数组列表一样工作,因此您可能会使用大部分附加内容来重建该数组。
Take a step through each element in the stack first, taking a count of the sum of all the string lengths.
Then you can use
String builder works like an array list, so you might be rebuilding that array with most of your appends.
一点小小的优化...将逗号测试放在循环之外。
其他建议是:
A bit of a mini-optimization... take the test-for-comma outside of the loop.
Other suggestions would be:
如果你的 mStack 是一个集合而不是数组,你可以只执行 mStack.toString() ,它将打印数组的可读字符串。这可能比自己编写更容易。
If your mStack is a Collection instead of an array, you can just do
mStack.toString()
, which will print a readable string of the array. That might be easier than writing your own.此方法中的 16% 运行时间包括还是排除调用的方法?如果 getCurrentMsg() 调用创建大量对象,则它可能是一个隐藏的问题。
我建议从堆栈中取出所有需要的字符串,然后
除此之外,
使用 。 org/lang/api-2.5/org/apache/commons/lang/StringUtils.html#join" rel="nofollow noreferrer">Apache 公共库。尝试依靠经过测试的代码来完成如此低级的事情,而不是每隔一天自己优化它。最终,这将为您带来更好的优化结果,因为您将能够专注于大局(即软件的整体设计)。
16% runtime in this method including or excluding called methods? The getCurrentMsg() call might be a hidden problem, if it creates lots of objects.
Besides that, I suggest to take all the needed Strings out of your stack and afterwards call
StringUtils.join(myStrings, ", ")
using the Apache commons library. Try relying on tested code for such low level things instead of optimizing it yourself every other day. In the end that will give you better optimization results because you will be able to concentrate on the big picture (i.e. the overall design of your software).
有一个带有字符串表示形式的 mStack 数组的单独副本,默认情况下用空字符串初始化,因此您的循环将是:
另外,创建具有足够容量的 StringBuilder:
因此,当您需要创建您只需简单地发送消息:
并且空部分不会引起问题,因为它们已经是空白的:
您甚至可以对它进行硬编码:
但这肯定会在未来造成更多的痛苦而不是缓解。
当您向 mStack 添加内容时:
只需复制消息并附加“,”即可。
根据空值的出现(如果它很低),您可以捕获它们,
这可怕
或者验证它:
我很确定您的方法正在做一些您没有向我们展示的其他事情。大概原因就在那里。
而且,如果 100% 是 1 秒,那么 16% 也不算太糟糕。
Have a separate copy of the
mStack
array with the string representation, by default initialized with empty String, so your loop would be:Also, create the StringBuilder with enough capacity:
So, when you need to create the message you would simply:
And empty parts won't cause a problem because they are blank already:
You may even hard code it:
But this would cause more pain than relief in the future, guaranteed.
When you add something to your mStack:
Just make a copy of the message and append the ", " already.
And depending on the occurrence of nulls ( if its low ) you can catch them
Which is horrendous
Or validate it:
I'm pretty sure your method is doing something else that you don't show us. Probably the reason is there.
Also, 16% is not that bad, if 100% is 1sec.
有时没有什么可以优化的。我认为这是这样的案例之一。您可以尝试删除一两条指令,但原则上您不会更快地得到它。
我认为唯一需要优化的是考虑为什么你调用它 18864 次以及是否可以完全避免其中一些调用。也许有些是不需要的,或者在某些情况下您可以缓存结果。
Sometimes there's just nothing else to optimize. I think this is one of such cases. You can try to shave off an instruction or two maybe, but you won't get it much faster in principle.
I think the only thing left to optimize is to consider why you are calling it 18864 times and whether some of those calls can be avoided altogether. Perhaps some are not needed, or perhaps you can cache the result in some cases.
使用 Apache Commons Lang 中的 StringBuilder + StringUtils。使用分隔符循环遍历字符串并进行 chomping 就是 StringUtils 的全部内容!
Apache Commons Lang 位于:http://commons.apache.org/lang/
Use StringBuilder + StringUtils from Apache Commons Lang. Looping through a String with a separator and chomping is what StringUtils is all about!
Apache Commons Lang is here: http://commons.apache.org/lang/