Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java for each与常规for——它们是等价的吗?_Java_Loops_Foreach_Syntactic Sugar - Fatal编程技术网

Java for each与常规for——它们是等价的吗?

Java for each与常规for——它们是等价的吗?,java,loops,foreach,syntactic-sugar,Java,Loops,Foreach,Syntactic Sugar,这两种结构是等价的吗 char[] arr = new char[5]; for (char x : arr) { // code goes here } 与之相比: char[] arr = new char[5]; for (int i = 0; i < arr.length; i++) { char x = arr[i]; // code goes here } char[]arr=新字符[5]; 对于(int i=0;i

这两种结构是等价的吗

char[] arr = new char[5];
for (char x : arr) {
    // code goes here
}
与之相比:

char[] arr = new char[5];
for (int i = 0; i < arr.length; i++) {
    char x = arr[i];
    // code goes here
}
char[]arr=新字符[5];
对于(int i=0;i
也就是说,如果我将完全相同的代码放在两个循环体中(并且它们进行编译),它们的行为会完全相同吗??



完整免责声明:这是受另一个问题()的启发。我的答案不是答案,但我觉得Java的确切语义有一些细微差别需要指出。

虽然这两种结构通常是可互换的,但它们并不是100%等价的。

可以通过定义
//此处的code
来构造证明,这将导致两个构造的行为不同。一个这样的循环体是:

arr = null;
因此,我们现在比较:

char[] arr = new char[5];
for (char x : arr) {
    arr = null;
}
与:

char[]arr=新字符[5];
对于(int i=0;i
这两个代码都可以编译,但如果运行它们,您会发现第一个循环正常终止,而第二个循环将抛出
NullPointerException

这意味着它们不是100%等价的!在某些情况下,这两种构造的行为会有所不同

这种情况可能很少见,但在调试时不应忘记这一事实,否则您可能会错过一些非常微妙的bug


作为附录,请注意,有时每个构造的索引甚至不是一个选项,例如,如果您需要索引。这里的关键教训是,即使它是一个选项,你也需要确保它实际上是一个等价的替代品,因为它并不总是有保证的

类似地,如果您从一个for-each循环开始,后来意识到需要切换到索引for循环,请确保您保留了语义,因为这并不能保证

特别是,要小心对正在迭代的数组/集合的引用进行任何修改(对内容的修改可能/可能不会触发
ConcurrentModificationException
,但这是另一个问题)


当使用使用自定义迭代器的集合时,保证语义保留也要困难得多,但如本例所示,即使涉及简单数组,这两种结构也不同。

第一种结构更具可读性,因此更可取,如果你无论如何都需要索引,那么就选择第二个。

它们几乎是等价的。但也有少数情况并非如此。最好使其成为最终版本

final char[] arr = new char[5];   // Now arr cannot be set null as shown 
                                  // in above answer.

即使这样,您也可以在第二个循环中执行
i--
。如果你不做这些不太可能的事情,它们基本上是等价的。

请注意,最重要的区别是“PolyGene润滑剂”给出的答案暗示了这一点,但没有明确说明:对于每个元素,都会迭代数组,但不能使用循环提供给你的实例修改任何元素(在本例中,变量“char x”)。经典循环允许您使用索引并更改数组的元素


编辑:快速更正。

我会立即、愉快地、错误地说:“是的,它们是完全等价的,因为第二种形式只是第一种形式的语法糖。”很好地指出了这一微妙的区别!感谢您花时间阅读本文。我希望其他人也能这样做,而不是一时兴起就投反对票。回答非常好,Polygene(+1).像Carl一样,我没有意识到存在这种细微的差异。谢谢你指出。你可能还想在你的答案中添加一个事实,即第二个可以让你访问某些情况下需要的索引。我对答案做了一些改进。请随意提出任何需要解决的问题。<代码中的True>我--
,但该代码无论如何都无法移植到for-each,因为它会引发编译时错误。尽管如此,
final
上的+1仍然是一件好事,只要适用。
final char[] arr = new char[5];   // Now arr cannot be set null as shown 
                                  // in above answer.