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

2022-09-02 11:31:11

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

例如,如果我有:

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

返回我要循环的数组的函数在哪里,函数是总是调用还是只调用一次?通常,使用此构造进行循环的代码有多最佳?getStringArray()


答案 1

关于增强型循环的语义for

以下是 Java 语言规范第 3 版的相关摘录,为清楚起见,稍作编辑:

JLS 14.14.2 语句的增强

增强语句的格式为:for

for ( Type Identifier : Expression ) Statement

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

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

其中 和 是编译器生成的标识符,与在发生增强语句时作用域中的任何其他标识符(编译器生成的或以其他方式)不同。aifor

因此,实际上该语言确实保证了它只会被评估一次。Expression

为了完整起见,以下是 is 类型时的等效性:ExpressionIterable

JLS 14.14.2 语句的增强

增强语句的格式为:for

for ( Type Identifier : Expression ) Statement

如果 的类型是 的子类型,则设为表达式 的类型。增强语句等效于以下形式的基本语句:ExpressionIterableIExpression.iterator()forfor

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

其中 是编译器生成的标识符,它与在发生增强语句时作用域中的任何其他标识符(编译器生成的或以其他方式)不同。iterfor

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


关于增强循环的性能for

以下是《有效的 Java 第 2 版》第 46 项中的一句话:比传统的 for 循环更喜欢 for-each 循环

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

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

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

另请参见


答案 2

JDK 1.4 引入了接口。它旨在为算法提供提示,对于给定的实现,迭代更有效:RandomAccessList

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

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

前循环是否考虑了这一点?还是它完全忽略了一个事实,即给定的可迭代实际上是一个列表?

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