简体   繁体   English

Java - for循环终止表达式之间的区别

[英]Java - Difference between for loop terminating expression

I'm just curious: Is there a difference on speed and performance between this two loops implementation? 我只是好奇:这两个循环实现之间的速度和性能是否存在差异? Assume that size() method returns the length of the array,collection, or object that handles a group of elements (actually it's from XOM api). 假设size()方法返回处理一组元素的数组,集合或对象的长度(实际上它来自XOM api)。

Implementation 1: 实施1:

int size = someArray.size();
for (int i = 0; i < size; i++) {
    // do stuff here
}

Implementation 2: 实施2:

for (int i = 0; i < someArray.size(); i++) {
    // do stuff here
}

From a performance point of view, there is little difference. 从性能的角度来看,差别不大。 This is because a loop can be optimized so that the size() lookup is inlined, resulting in very little performance difference. 这是因为可以优化循环,以便内联size()查找,从而导致性能差异很小。

The main difference is if the size changes while looping. 主要区别在于循环时大小是否发生变化。 The first case will try to iterate a fixed number of times. 第一种情况将尝试迭代固定次数。 In the second case, the number of iterations will depend on the final size(). 在第二种情况下,迭代次数将取决于最终大小()。

The 1st snippet is bound to execute faster since it calls size() once only. 第一个片段绑定执行得更快,因为它只调用一次size() The 2nd snippet calls size() N times. 第二个片段调用size() N次。 Depending on the impl. 取决于impl。 it might pose significant penalty, esp. 它可能会造成重大的惩罚,尤其是 if the compiler finds hard to inline the method and/or the size() method doesn't just return non-volatile variable, etc. 如果编译器发现难以内联方法和/或size()方法不仅返回非易失性变量等。

I'd have rewritten it like for(int i=0, s=someCollection.size(); i<s; i++) 我已经重写了它for(int i=0, s=someCollection.size(); i<s; i++)

Note: arrays don't have size() method. 注意:数组没有size()方法。

Yes, there is a difference. 是,有一点不同。 In the first loop, the size() method is only called once. 在第一个循环中,size()方法只调用一次。 In the second one, it's called at each iteration. 在第二个中,它在每次迭代时调用。

If the iteration modifies the size of the collection (which is very very uncommon), the second one is needed. 如果迭代修改了集合的大小(这是非常罕见的),则需要第二个。 In most cases, you should prefer the first one, but limit the scope of the size variable : 在大多数情况下,您应该更喜欢第一个,但是限制size变量的范围:

for (int i = 0, size = someArray.size(); i < size; i++) {
    // ...
}

But most of the time, you should prefer the foreach syntax anyway : 但大多数时候,你应该更喜欢foreach语法:

for (Foo foo : collection) {
    // ...
}

which will iterate over the array or collection efficiently, even for a LinkedList for example, where indexed access is not optimal. 这将有效地迭代数组或集合,即使对于LinkedList,例如索引访问不是最佳的。

Don't worry about it, JVM optimization is very aggressive these days. 不要担心,JVM优化这些天非常具有攻击性。

Use the 2nd form, for it's more readable, and most likely as fast. 使用第二种形式,因为它更具可读性,而且最有可能。 Premature optimization yada yada. 过早优化yada yada。

And when you do need to improve speed, always profile first, don't guess. 当你确实需要提高速度时,总是首先进行剖析,不要猜测。

It is extremely unlikely that caching size() in a local variable could benefit your app noticeably. 局部变量中的缓存size()极不可能显着地使您的应用受益。 If it does, you must be doing simple operations over a huge dataset. 如果是这样,您必须对庞大的数据集进行简单的操作。 You shouldn't use ArrayList at all in that case. 在这种情况下,你根本不应该使用ArrayList。

Always avoid anything that can be done outside of the loop like method calls, assigning values to variables, or testing for conditions. 始终避免在方法调用之外可以在循环之外完成的任何操作,为变量赋值或测试条件。

Method calls are more costly than the equivalent code without the call, and by repeating method calls again and again, you just add overhead to your application. 方法调用比没有调用的等效代码更昂贵,并且通过一次又一次地重复方法调用,您只需向应用程序添加开销。

Move any method calls out of the loop, even if this requires rewriting of the code. 将任何方法调用移出循环,即使这需要重写代码。

Benefits :- 好处: -

Unless the compiler optimizes it, the loop condition will be calculated for each iteration over the loop. 除非编译器对其进行优化,否则将为循环上的每次迭代计算循环条件。

If the condition value is not going to change, the code will execute faster if the method call is moved out of the loop. 如果条件值不会改变,则如果方法调用移出循环,代码将执行得更快。

Note :- 注意 :-

If the method returns a value that will not change during the loop, then store its value in a temporary variable before the loop. 如果方法返回的值在循环期间不会更改,则在循环之前将其值存储在临时变量中。

Hence its value is stored in a temporary variable size outside the loop, and then used as the loop termination condition. 因此,它的值存储在循环外部的临时变量大小中,然后用作循环终止条件。

Maybe it is worth to note that this construct: 也许值得注意的是这个结构:

for (String s : getStringsList()) {
    //...
}

invokes getStringsList() only once and then operates on iterator behind the scenes. 仅调用getStringsList()一次,然后在后台操作迭代器。 So it is safe to perform lengthy operations or change some state inside getStringsList() . 因此,在getStringsList()执行冗长的操作或更改某些状态是安全的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM