我刚刚开始学习Java,我遇到的第一件事是foreach
循环,我不知道它的工作方式我做的第一件事是:
int[] array = new int [10];
for (int i: array){
i = 1;
}
显然未能将1
分配给数组的每个元素。然后我将System.out.print(i);
(在i = 1;
之后)添加到循环体中并看到屏幕的输出为1111111111
但是因为在循环内部使用i
做了一些事情是有效的是,i
很可能是数组中每个元素的副本,不是吗? (第一个问题)
如果上述情况属实,这并不意味着foreach
循环比公共for循环要慢得多,因为它涉及制作数组中每个元素的副本?或者由于Java
没有指针和指针算术,oprator[]
可能会以其他“严重”的方式设计,复制每个元素实际上更快?
如果上述假设为真,为什么会使用明显较慢的foreach
循环而不是常见的for
循环呢?
简而言之:
i
的每个元素的副本是array
吗?如果不是这样的话
然后
foreach
循环不是常见的慢吗?如果没有,怎么样
那么“很糟糕”是operator[]
设计的吗?
除foreach
循环中的可读性外,没有其他内容了吗?
答案 0 :(得分:11)
在代码中
for (int i: array){
您声明一个变量i
,在每次循环迭代中获取数组中下一个元素的值,它不是对该元素的引用。
在
i = 1;
为变量赋值,而不是为数组中的元素赋值。
您无法直接使用foreach循环设置数组元素的值。使用正常的for
循环
for (int i = 0; i < array.length; i++) {
array[i] = ...; // some value
}
在上面的示例中,您使用声明的变量i
作为数组中元素的索引。
array[i]
正在访问您可以修改其值的元素本身。
Ans显然无法为数组的每个元素分配1。我 添加了System.out.print(i);到了循环的身体,看到了 屏幕输出是1111111111,但自从做了一些事情 循环内部有效,我很可能是每个元素的副本 阵列,不是吗? (第一个问题)
您必须将System.out.print(i)
放在i = 1
之后,否则您将获得0000000
。
如果上述情况属实,则不意味着foreach循环很多 慢于普通for循环,因为它涉及制作副本 数组的每个元素?或者因为Java没有指针和 指针运算,oprator []可能在其他一些设计 复制每个元素的“非常”时尚实际上更快?
看看here,了解foreach循环的工作原理。对于数组,
for (int i: array){
i = 1;
}
相当于
for (int index = 0; index < array.length; index++) {
int i = array[index];
i = 1;
}
所以它并不慢。你正在堆栈上做一个更原始的创作。
这取决于实施。对于数组,它不会以任何方式变慢。它只是用于不同的目的。
为什么人们会使用明显较慢的foreach循环而不是常见的循环 for循环?
一个原因是可读性。另一个是当你不关心更改数组的元素引用时,而是使用当前引用。
参考类型示例
public class Foo {
public int a;
}
Foo[] array = new Foo[3];
for (int i = 0; i < array.length; i++) {
array[i] = new Foo();
array[i].a = i * 17;
}
for (Foo foo : array) {
foo.a = 0; // sets the value of `a` in each Foo object
foo = new Foo(); // create new Foo object, but doesn't replace the one in the array
}
对于原始类型,这样的东西不起作用。
for (int index = 0; index < array.length; index++) {
int i = array[index];
i = 1; // doesn't change array[index]
}
答案 1 :(得分:6)
来自Joshua Bloch的Effective Java中的第46项:
在1.5版中引入的for-each循环消除了混乱 以及隐藏迭代器或索引变量的错误机会 完全。由此产生的习语同样适用于集合和 阵列:
// The preferred idiom for iterating over collections and arrays for (Element e : elements) { doSomething(e); }
当你看到冒号(:)时,将其读作“in”。因此,上面的循环 读为“元素中的每个元素e”。请注意,没有 使用for-each循环的性能损失,即使对于数组也是如此。在 事实上,它可能比普通的性能提供轻微的性能优势 在某些情况下循环,因为它计算数组的限制 索引只有一次。虽然你可以手工(第45项),程序员 不要总是这样做。
<强>优点强>
- 可读性
- 它增加了抽象级别 - 而不是必须表达如何循环列表的低级细节 或者数组(使用索引或迭代器),开发人员只是说明了这一点 他们想要循环,而语言会照顾其余部分。
醇>
<强>缺点:强>
无法访问索引或删除项目。
总结一下,
增强的for循环提供
- 醇>
用于循环遍历列表或数组的简洁高级语法
1.1提高了清晰度
1.2可读性。
然而,它错过了:允许访问索引循环或删除项目。
答案 2 :(得分:3)
通过引用设置值不起作用,因为int
是基本类型。对于任何类型的Object [],它都可以工作。制作原始类型的副本非常快,并且很多次都会由处理器完成而没有你意识到。
foreach
循环更具可读性,但它也更易于编写。常见的程序员错误是:
for (int i = 0; i < 10; i++)
{
for(int j = 0; j < 10; i++) //oops, incrementing wrong variable!
{
//this will not execute as expected
}
}
使用foreach
循环无法发出此错误。
答案 3 :(得分:2)
for语句还有另一个用于迭代集合和数组的表单。这个表单有时被称为增强for语句,可用于使循环更紧凑和易于阅读。 http://docs.oracle.com/javase/tutorial/java/nutsandbolts/for.html
所以,你是对的。可读性是这里的主要胜利。有关for each循环或增强for循环的更多信息,请参阅blog entry from oralce。
每个都使用了Iterable<E>
接口的功能,因此性能取决于实现。