3

可能重复:
for循环优化

假设我们要遍历 string 的字符s。我想说以下代码或多或少是默认代码。

for( int i = 0; i < s.length(); i++ ) {
    doSomethingWith( s.charAt( i ) );
}

问题 #1:为什么我经常看到以下内容?

final int length = s.length();
for( int i = 0; i < length; i++ ) {
    doSomethingWith( s.charAt( i ) );
}

乍一看,这似乎是合理的,因为每次迭代都会评估不等式。但是,我希望 VM 无论如何都会对此进行优化,因为字符串是不可变的。有什么想法吗?如果我们迭代一个可变结构(没有被任何其他线程引用)怎么办?如果length()不能保证在 O(1) 中运行怎么办?

问题 #2:有些人似乎认为替代++i可以i++加快代码速度。他们是对的吗?同样,这不是我所期望的,但我只是不确定。

我们都知道不要过早优化。同时,如果我们能够以几乎不花费任何代价来生成稍微快一点的代码,那么我们不这样做就太愚蠢了。当然,有人可能会争辩说这两种“优化”都会损害可读性,但在我看来,损害是如此之小,以至于在某些情况下它是合理的。

我试图衡量性能上的任何差异,但很难得出结论性的结果。尽管这应该适用于任何特定的应用程序,但我的目标是在这里获得洞察力和一般性答案。

(虽然我在写这篇文章时考虑到了 HotSpot VM,但考虑其他平台也可能很有趣,比如移动设备。)

4

2 回答 2

5

问题 #1:为什么我经常看到以下内容?

第一个例子是过早的优化。人们这样做的原因是他们通常不会分析他们的代码以查看真正的瓶颈在哪里,而只是尝试猜测。

如果不能保证 length() 在 O(1) 中运行怎么办?

那么进行这种优化会更有意义。如果您知道计算长度是一项昂贵的操作并且值不会改变,那么计算一次并存储结果可能会提高性能。

问题 #2:有些人似乎认为用 ++i 代替 i++ 可以加快代码速度。他们是对的吗?同样,这不是我所期望的,但我只是不确定。

他们是不对的。他们的论点是i++必须创建变量的临时副本,而++i没有。很久以前,当编译器不擅长优化时,这在 C 或 C++ 中曾经是正确的。Java 并非如此。

于 2012-08-24T19:35:29.403 回答
3

乍一看,这似乎是合理的,因为每次迭代都会评估不等式。但是,我希望 VM 无论如何都会对此进行优化,因为字符串是不可变的。

编译器对此进行了优化。像那样做i < s.length();就好了。

有些人似乎认为用 ++i 代替 i++ 可以加快代码速度。

它不会,除非你给 ++i 的返回值赋值

于 2012-08-24T19:35:41.963 回答