java Java的for循环代码是如何由编译器生成的

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3433282/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 01:50:00  来源:igfitidea点击:

How is Java's for loop code generated by the compiler

javaforeach

提问by Nikhil Garg

How is Java's for loop code generated by the compiler?

Java 的 for 循环代码是如何由编译器生成的?

For example, if I have:

例如,如果我有:

for(String s : getStringArray() )
{
   //do something with s
}

where getStringArray()is a function that returns the Array I want to loop on, would function be called always or only once? How optimal is the code for looping using this construct in general?

getStringArray()返回我想要循环的数组的函数在哪里,是始终调用函数还是仅调用一次函数?一般而言,使用此构造的循环代码的优化程度如何?

回答by polygenelubricants

On the semantics of enhanced forloop

论增强for循环的语义

Here is the relevant excerpts from the Java Language Specification 3rd Edition, slightly edited for clarity:

以下是Java Language Specification 3rd Edition的相关摘录,为清晰起见,略作编辑:

JLS 14.14.2 The enhanced forstatement

The enhanced forstatement has the form:

for ( Type Identifier : Expression ) Statement

If the type of Expressionis an array type, T[], then the meaning of the enhanced forstatement is given by the following basic forstatement:

T[] a = Expression;
for (int i = 0; i < a.length; i++) {
    Type Identifier = a[i];
    Statement
}

where aand iare compiler-generated identifiers that are distinct from any other identifiers (compiler-generated or otherwise) that are in scope at the point where the enhanced forstatement occurs.

JLS 14.14.2 增强for语句

增强for语句具有以下形式:

for ( Type Identifier : Expression ) Statement

如果的类型Expression是数组类型,T[]则增强for语句的含义由以下基本for语句给出:

T[] a = Expression;
for (int i = 0; i < a.length; i++) {
    Type Identifier = a[i];
    Statement
}

其中ai是编译器生成的标识符,它们不同于在增强for语句出现点的范围内的任何其他标识符(编译器生成的或其他方式)。

So in fact the language does guarantee thatExpressionwill only be evaluated once.

所以事实上该语言确实保证Expression只会被评估一次。

For completeness, here's the equivalence when the Expressionis of type Iterable:

为完整起见,当Expressionis 为 type时,这里是等价的Iterable

JLS 14.14.2 The enhanced forstatement

The enhanced forstatement has the form:

for ( Type Identifier : Expression ) Statement

If the type of Expressionis a subtype of Iterable, then let Ibe the type of the expression Expression.iterator(). The enhanced forstatement is equivalent to a basic forstatement of the form:

for (I iter = Expression.iterator(); iter.hasNext(); ) {
    Type Identifier = iter.next();
    Statement
}

where iteris a compiler-generated identifier that is distinct from any other identifiers (compiler-generated or otherwise) that are in scope at the point where the enhanced forstatement occurs.

JLS 14.14.2 增强for语句

增强for语句具有以下形式:

for ( Type Identifier : Expression ) Statement

如果 的类型Expression是 的子类型Iterable,则 letI是表达式的类型Expression.iterator()。增强for语句等效于for以下形式的基本语句:

for (I iter = Expression.iterator(); iter.hasNext(); ) {
    Type Identifier = iter.next();
    Statement
}

其中iter是编译器生成的标识符,它与增强for语句发生点范围内的任何其他标识符(编译器生成的或其他方式的)不同。

Note that it is a compile-time error if Expressionis neither an Iterablenor an array, so the above two are the only cases where you can use an enhanced forloop. Also, for clarity, the above quotes leave out information regarding any labels attached on the forloop and any modifiers attached on the Identifier, but these are handled as one would expect.

请注意,如果Expression既不是 anIterable也不是数组,则这是编译时错误,因此上述两种情况是您可以使用增强for循环的唯一情况。此外,为了清楚起见,上面的引用省略了有关for循环上附加的任何标签和 上附加的任何修饰符的信息Identifier,但这些都按预期进行处理。



On the performance of enhanced forloop

关于增强for循环的性能

Here's a quote from Effective Java 2nd Edition, Item 46: Prefer for-each loops to traditional for loops

这是Effective Java 2nd Edition, Item 46的引述:Prefer for-each 循环而不是传统的 for 循环

The for-each loop, introduced in release 1.5, gets rid of the clutter and the opportunity for error by hiding the iterator or index variable completely. The resulting idiom applies equally to collections and arrays. Note that there is no performance penalty for using the for-each loop, even for arrays. In fact, it may offer a slight performance advantage over an ordinary forloop in some circumstances, as it computes the limit of the array index only once. While you cando this by hand, programmers don't always do so.

1.5 版中引入的 for-each 循环通过完全隐藏迭代器或索引变量来消除混乱和出错的机会。由此产生的习语同样适用于集合和数组。请注意,使用 for-each 循环没有性能损失,即使对于数组也是如此。事实上,for在某些情况下,它可能比普通循环提供轻微的性能优势,因为它只计算一次数组索引的限制。虽然您可以手动完成此操作,但程序员并不总是这样做。

Thus the book claims that in fact some compilers go beyond the JLS translation and performs additional optimization on the for-each loop (while still maintaining its semantics, of course).

因此,这本书声称实际上一些编译器超越了 JLS 翻译,并对 for-each 循环执行了额外的优化(当然,同时仍然保持其语义)。

In summary, you should not worry about the performance of for-each loop. The specification by the language is sensible (Expressiononly evaluated once), and precisely because this is the preferred construct in many scenarios, compilers will make sure to optimize them as best they can.

总之,您不必担心 for-each 循环的性能。语言的规范是合理的(Expression只评估一次),正是因为这是许多场景中的首选构造,编译器将确保尽其所能优化它们。

See also

也可以看看

回答by Guillaume Holler

JDK 1.4 introduced the RandomAccessinterface. It is meant to give a hint to algorithms when, for a given Listimplementation, it is more efficient to iterate through:

JDK 1.4 引入了该RandomAccess接口。它旨在为算法提供提示,对于给定的List实现,迭代执行以下操作更有效:

for (int i = 0, n = list.size(); i < n; i++) {
    list.get(i);
}

than

for (Iterator i = list.iterator(); i.hasNext(); ) {
   i.next();
}

Does the foreach loop take this into account? Or does it completely ignore the fact that a given Iterable is in fact a List?

foreach 循环是否考虑到了这一点?或者它是否完全忽略了一个事实,即给定的 Iterable 实际上是一个 List?

It should be noted that this would imply that adding a (iterable instanceof List && iterable instanceof RandomAccess)test and a downcast to Listwould work, which would add an overhead that's not always worth it and could be considered a premature optimization for a compiler syntactic sugarfeature.

应该注意的是,这意味着添加一个(iterable instanceof List && iterable instanceof RandomAccess)测试和向下转换 toList会起作用,这会增加并不总是值得的开销,并且可能被认为是对编译器语法糖功能的过早优化。

回答by fastcodejava

Compiler might call it just once, but you candepend on it. It may not be a good coding practice. If getStringArray()returns same array each time, why not set to a variable first?

编译器可能只调用一次,但您可以依赖它。这可能不是一个好的编码习惯。如果getStringArray()每次都返回相同的数组,为什么不先设置一个变量呢?

EDIT- answer changed with the comments received.

编辑- 答案随着收到的评论而改变。

回答by borris

for loop is same like loop in javascript so no need to afraid

for 循环与 javascript 中的循环相同,因此无需担心

example:

例子:

for(int i=0;i<10;i++)
{
    System.out.Println(i);
}