虽然这两种结构通常是可互换的,但它们并不是100%等效的!!!
可以通过定义来证明,这将导致两个构造的行为不同。一个这样的循环体是:// code goes here
arr = null;
因此,我们现在正在比较:
char[] arr = new char[5];
for (char x : arr) {
arr = null;
}
跟:
char[] arr = new char[5];
for (int i = 0; i < arr.length; i++) {
char x = arr[i];
arr = null;
}
这两个代码都会编译,但是如果运行它们,您会发现第一个循环正常终止,而第二个循环将抛出一个 .NullPointerException
这意味着它们不是100%等效的!在某些情况下,这两种结构的行为会有所不同!
这种情况可能很少见,但在调试时不应忘记这一事实,因为否则您可能会错过一些非常微妙的错误。
作为附录,请注意,有时 for-each 构造甚至不是一个选项,例如,如果您需要索引。这里的关键教训是,即使它是一种选择,你也需要确保它实际上是一个等效的替代品,因为它并不总是得到保证。
同样,如果您从 for-each 循环开始,后来意识到需要切换到索引 for 循环,请确保保留语义,因为它不能保证。
特别是,_be对数组/集合引用的任何修改都iterated_(对内容的修改可能/可能不会触发,但这是一个不同的问题)。ConcurrentModificationException
当您使用使用自定义迭代器的集合时,保证语义保留也要困难得多,但如本例所示,即使涉及简单数组,这两种构造也是不同的。