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

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (32)

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

例如,如果我有:

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

在哪里getStringArray()是一个返回我想循环的数组的函数,函数会被始终调用还是只调用一次?一般来说,使用这个结构循环的代码有多优化?

提问于
用户回答回答于

JDK 1.4引入了RandomAcces界面。这是为了给算法提示,对于给定的List实现,迭代更有效:

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

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

foreach循环是否考虑到了这一点?还是它完全忽略了一个事实:给定的Iterable实际上是一个List ?. 应该注意的是,这意味着要向(iterable instanceof List && iterable instanceof RandomAccess)List 添加一个测试和一个downcast,这会增加一个并不总是值得的开销,并且可能被认为是编译器语法糖特征的预先优化。

用户回答回答于

关于增强for环路的语义

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

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语句出现点处的范围内的任何其他标识符(编译器生成的或其他标识符)不同。

所以实际上这种语言确保 Expression 只会评估一次。

为了完整起见,这里的等价时Expression的类型为Iterable

JLS 14.14.2增强for声明 增强的for声明具有以下形式: for ( Type Identifier : Expression ) Statement 如果类型Expression是一个子类型Iterable,那么让它I成为表达式的类型Expression.iterator()。增强的for声明等同于for表单的基本声明: for (I iter = Expression.iterator(); iter.hasNext(); ) { Type Identifier = iter.next(); Statement } 在哪里iter是一个编译器生成的标识符,它与增强for语句出现点范围内的任何其他标识符(编译器生成的或其他标识符)不同。

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

关于增强for环路的性能

以下是来自Effective Java第2版的第46项:Prefer for-每个循环到传统的for循环

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

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

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

也可以看看

扫码关注云+社区