在我看来,其他答案是基于不正确的基准,没有考虑到 Hotspot 的编译和优化过程。
简答
尽可能使用增强循环,因为大多数情况下它是最快的。
如果不能,请尽可能将整个数组拉入局部变量:
int localArray = this.array;
for (int i = 0; i < localArray.length; i++) {
methodCall(localArray[i]);
}
长答案
现在,通常没有区别,因为 Hotspot 非常擅长优化和摆脱 java 需要做的检查。
但有时某些优化无法完成,通常是因为您在循环中有一个虚拟调用,无法内联。
在这种情况下,某些循环确实会比其他循环更快。
Java 需要做的几件事:
-
重新加载 this.array - 因为它可以被更改(通过调用或其他线程)
-
检查i是否在数组的范围内,如果不在抛出IndexOutOfBoundsException
-
检查访问的对象引用是否为空,如果是抛出 NullPointerException
考虑一下这个 c 风格的循环:
for (int i = 0; i < this.array.length; i++) { //now java knows i < this.array.length
methodCall(this.array[i]);// no need to check
}
通过评估循环条件 i ,java 知道 i 必须在范围内(i仅在调用之后更改),因此无需再次检查在下一行。
但在这种情况下,java 需要重新加载 this.array.length。
您可能想通过将 this.array.length 值拉到局部变量中来“优化”循环:
int len = this.array.length;//len is now a local variable
for (int i = 0; i < len; i++) { //no reload needed
methodCall(this.array[i]); //now java will do the check
}
现在java不需要每次都重新加载,因为局部变量不能被methodCall和/或另一个线程改变。局部变量只能在方法内部改变,java现在可以证明变量len不能改变。
但是现在循环条件 i 变成了 i ,并且之前的优化失败,java需要检查i是否在this.array的范围内。
更好的优化是将整个数组拉入一个局部变量:
int localArray = this.array;
for (int i = 0; i < localArray.length; i++) {
methodCall(localArray[i]);
}
现在java不需要重新加载数组了,“i in bounds”的检查也取消了。
那么增强循环呢?
好吧,通常编译器会将您的增强循环重写为类似于最后显示的循环,如果不是更好的话。