This question already has an answer here:
这个问题在这里已有答案:
- Why is declaration of the variable required inside a for-each loop in java 4 answers
为什么在java 4中for-each循环内所需的变量声明应答
According to the Java Language Specification, § 14.14.2, the variable of an enhanced for
loop must be local to the loop. In other words, this compiles:
根据Java语言规范,§14.14.2,增强的for循环的变量必须是循环的本地变量。换句话说,这编译:
for (State state : State.values()) {
// do something for each state
}
but this does not:
但这不是:
State state;
for (state: State.values()) {
// do something for each state
}
The JLS gives no rationale for this language design choice. I can see why the type name must be present if the local variable is modified by final
or by an annotation, but I don't understand why a bare name of a variable declared elsewhere isn't allowed. Does anyone have any insight into why this restriction was imposed?
JLS没有给出这种语言设计选择的理由。我可以看到为什么类型名称必须存在,如果局部变量被final或注释修改,但我不明白为什么不允许在其他地方声明的变量的裸名称。有没有人知道为什么要施加这种限制?
EDIT
Several answers so far seem to be suggesting that what happens outside the loop is reason for designing the language this way. Perhaps a closer examination of what the JLS says will clarify why I don't find this convincing. Consider this loop, where State
is an enum:
到目前为止,几个答案似乎暗示在循环外发生的事情是以这种方式设计语言的原因。也许仔细研究JLS所说的将澄清为什么我没有发现这令人信服。考虑这个循环,其中State是枚举:
for (State state : State.values()) {
// ...
}
State.values()
is an array, so according to the JLS, the loop is functionally identical to:
State.values()是一个数组,因此根据JLS,循环在功能上与:
State[] a = State.values();
for (int i = 0; i < a.length; i++) {
State state = a[i];
// ...
}
Now clearly this latter loop could have been written:
现在显然可以编写后一个循环:
State state;
State[] a = State.values();
for (int i = 0; i < a.length; i++) {
state = a[i];
// ...
}
Conceptually, this last (perfectly legal) loop could have been used as the functional equivalent of the second enhanced for
loop above (the one that does not compile).
从概念上讲,这最后一个(完全合法的)循环可以用作上面第二个增强for循环(不编译的循环)的功能等价物。
Similarly, if stateList
is an Iterable<State>
(not an array), this loop:
类似地,如果stateList是Iterable
for (State state : stateList) {
// ...
}
is functionally identical to:
在功能上与:
for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) {
State state = iterator.next();
// ...
}
Like before, this latter loop could have been written:
像以前一样,后一个循环可能已写入:
State state;
for (Iterator<State> iterator = stateList.iterator(); iterator.hasNext(); ) {
state = iterator.next();
// ...
}
Again, this could have been used as the functional equivalent of the (illegal):
同样,这可能被用作(非法)的功能等价物:
State state;
for (state : stateList) {
// ...
}
In each case, when the loop exits, the value of state
is perfectly well defined (if, perhaps, useless). Also, just as with the regular loop, an enhanced for
loop using a bare variable name that was not defined (e.g., the line State state;
was missing or out of scope) could be caught at compile time. So from a language design perspective, what's the problem? Why did the language designers outlaw this construct?
在每种情况下,当循环退出时,状态的值被完美地定义(如果,也许,无用)。此外,与常规循环一样,使用未定义的裸变量名称(例如,行状态;缺少或超出范围)的增强for循环可以在编译时捕获。那么从语言设计的角度来看,问题是什么?为什么语言设计者禁止这种结构?
5 个解决方案
#1
9
One benefit/rationale is local variables dont pollute your code. Let me give a normal loop example (this is just for analogy not an exact one, so no iterator use):
一个好处/基本原理是局部变量不会污染您的代码。让我给出一个正常的循环示例(这只是为了类比而不是一个精确的,所以没有使用迭代器):
int i;
for(i=0;i<10;i++)
do...something
int j;
for(j=0; i<10; j++)
do...something
Now in the above code if look closely you will find a potential bug. i
has been mistakenly used in loop which iterates over j
.
现在在上面的代码中,如果仔细观察,你会发现一个潜在的错误。我被错误地用在循环中,迭代j。
So enhanced loops try to play safe by creating the variables locally, by which you can avoid above problem.
所以增强的循环试图通过在本地创建变量来保证安全,通过它可以避免上述问题。
#2
11
Look at how the for-each loop internally works, see How does the Java 'for each' loop work?
看看for-each循环内部如何工作,请参阅每个循环的Java'如何工作?
for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
String item = i.next();
System.out.println(item);
}
Each time it declares the String variable item. Hence in your case its doing essentially
每次声明String变量项。因此,在你的情况下,它基本上做
State state;
\\and inside
State state = i.next();
which obviously wont work. Now inside the implementation, they it could rather only do
这显然不会工作。现在在实现中,他们只能这样做
item = i.next();
but then you always have to define that item outside for-each, which would be pain majority of time.
但是你总是必须在每个外面定义该项目,这在大多数情况下会很痛苦。
#3
7
A lot of decisions in Java are more based on the concept of why "Wouldn't" you remove x. Why on earth allow your code to be confused by moving the scope outside the loop? If you really needed access to the last element afterwards there are cleaner ways.
Java中的许多决策更多地基于为什么“不会”删除x的概念。为什么通过将范围移到循环外来让您的代码混淆?如果你真的需要访问最后一个元素,那么有更简洁的方法。
I suppose some may argue one way or another as to protecting programmers from themselves, I look at it more as Java protects me from people who like to take advantage of things like this.
我想有些人可能会以这样或那样的方式争论保护程序员自己,我更多地看待它,因为Java保护我免受那些喜欢利用这类事情的人的影响。
It's not really a great hobby language, it is a great team development language where the point is to make it as easy as possible for the next guy to understand your code.
它不是一种非常好的爱好语言,它是一种很棒的团队开发语言,其重点是让下一个人能够轻松理解你的代码。
For instance, I saw in a comment above that many people break out of a for loop at a certain point with a value. How clear is that when you are scanning through code trying to find a bug? It's people using neat tricks like this that I really want to be protected from, not myself.
例如,我在上面的评论中看到,许多人在某个特定点突破了一个for循环。当您扫描代码试图找到错误时,有多清楚?这是人们使用这样的巧妙技巧,我真的想要保护,而不是我自己。
If you wish to execute some code mid-loop, put it in a method and call it from within the loop.
如果您希望在循环中执行一些代码,请将其放在方法中并从循环内调用它。
The lack of cute tricks often makes me re-think my code and work a little harder--but the results are always more readable/maintainable.
缺乏可爱的技巧常常让我重新思考我的代码并且工作稍微努力 - 但结果总是更易读/可维护。
If you are just a single programmer (Not on a team) I'd advise against Java, It doesn't do neat tricks and you won't see cool yearly feature updates--and it is fairly slow to program in (It moves a lot of time catching and fixing bugs into time spent coding, frustrating people with it's strict rules (One of the biggest advantages of the language IMO)
如果你只是一个程序员(不在一个团队中),我会建议不要使用Java,它不会做很好的技巧,你也不会看到很酷的年度功能更新 - 而且编程速度相当慢(它移动很多时候将错误捕获并修复到编码所花费的时间,用严格的规则来挫败人们(IMO语言的最大优势之一)
If you want something javaish try Scala instead. If you are "Forced" to learn it because of a classroom decision then you might want to attempt to appreciate it from the "team" point of view and with the mindset that you won't be forced to use it in the future.
如果你想要一些javaish尝试Scala而不是。如果你因为课堂决定而“*”去学习它,那么你可能想要尝试从“团队”的角度来理解它,以及你将来不会*使用它的心态。
#4
5
They might have wanted to remove a possible difference in semantics between the simple for and the enhanced for.
他们可能想要删除simple for和enhanced for之间可能存在的语义差异。
If you had, say, a regular for loop:
如果你有一个常规for循环:
int i;
for (i=0; i<4; i++)
;
then if you let the loop execute normally, you get that i==4
after the loop, which is not valid for the iteration variable.
那么如果你让循环正常执行,你会在循环之后得到i == 4,这对迭代变量无效。
What then, if you could have:
然后,如果你可以:
int i;
for (i : myArray)
;
I suppose from an implementation standpoint, it would be easiest if at the end i
were equal to the last element in the array. But should it behave like that or should there be some invalid value, and if so, what could that be? What if you break out of the last iteration?
我想从实现的角度来看,如果最后我等于数组中的最后一个元素,那将是最简单的。但是它应该表现得那样还是应该有一些无效的价值,如果是这样,那会是什么呢?如果你突破上一次迭代怎么办?
Another possibility is that it makes it more clear what that loop is about and what the element type of the collection is. By contrast, the simple for is a "legacy" construct in some sense, so they couldn't have applied a similar logic without "breaking" it or limiting its flexibility.
另一种可能性是它更清楚地说明了循环是什么以及集合的元素类型是什么。相比之下,简单的是某种意义上的“遗留”构造,因此它们不能在不“破坏”它或限制其灵活性的情况下应用类似的逻辑。
I'm obviously speculating, and it could turn out to have just been a random design choice.
我显然在猜测,它可能只是一个随机的设计选择。
#5
3
Maybe because in this way, it guarantees that state
will be empty and has no initial value assigned to it.
也许是因为以这种方式,它保证状态为空并且没有分配给它的初始值。
#1
9
One benefit/rationale is local variables dont pollute your code. Let me give a normal loop example (this is just for analogy not an exact one, so no iterator use):
一个好处/基本原理是局部变量不会污染您的代码。让我给出一个正常的循环示例(这只是为了类比而不是一个精确的,所以没有使用迭代器):
int i;
for(i=0;i<10;i++)
do...something
int j;
for(j=0; i<10; j++)
do...something
Now in the above code if look closely you will find a potential bug. i
has been mistakenly used in loop which iterates over j
.
现在在上面的代码中,如果仔细观察,你会发现一个潜在的错误。我被错误地用在循环中,迭代j。
So enhanced loops try to play safe by creating the variables locally, by which you can avoid above problem.
所以增强的循环试图通过在本地创建变量来保证安全,通过它可以避免上述问题。
#2
11
Look at how the for-each loop internally works, see How does the Java 'for each' loop work?
看看for-each循环内部如何工作,请参阅每个循环的Java'如何工作?
for(Iterator<String> i = someList.iterator(); i.hasNext(); ) {
String item = i.next();
System.out.println(item);
}
Each time it declares the String variable item. Hence in your case its doing essentially
每次声明String变量项。因此,在你的情况下,它基本上做
State state;
\\and inside
State state = i.next();
which obviously wont work. Now inside the implementation, they it could rather only do
这显然不会工作。现在在实现中,他们只能这样做
item = i.next();
but then you always have to define that item outside for-each, which would be pain majority of time.
但是你总是必须在每个外面定义该项目,这在大多数情况下会很痛苦。
#3
7
A lot of decisions in Java are more based on the concept of why "Wouldn't" you remove x. Why on earth allow your code to be confused by moving the scope outside the loop? If you really needed access to the last element afterwards there are cleaner ways.
Java中的许多决策更多地基于为什么“不会”删除x的概念。为什么通过将范围移到循环外来让您的代码混淆?如果你真的需要访问最后一个元素,那么有更简洁的方法。
I suppose some may argue one way or another as to protecting programmers from themselves, I look at it more as Java protects me from people who like to take advantage of things like this.
我想有些人可能会以这样或那样的方式争论保护程序员自己,我更多地看待它,因为Java保护我免受那些喜欢利用这类事情的人的影响。
It's not really a great hobby language, it is a great team development language where the point is to make it as easy as possible for the next guy to understand your code.
它不是一种非常好的爱好语言,它是一种很棒的团队开发语言,其重点是让下一个人能够轻松理解你的代码。
For instance, I saw in a comment above that many people break out of a for loop at a certain point with a value. How clear is that when you are scanning through code trying to find a bug? It's people using neat tricks like this that I really want to be protected from, not myself.
例如,我在上面的评论中看到,许多人在某个特定点突破了一个for循环。当您扫描代码试图找到错误时,有多清楚?这是人们使用这样的巧妙技巧,我真的想要保护,而不是我自己。
If you wish to execute some code mid-loop, put it in a method and call it from within the loop.
如果您希望在循环中执行一些代码,请将其放在方法中并从循环内调用它。
The lack of cute tricks often makes me re-think my code and work a little harder--but the results are always more readable/maintainable.
缺乏可爱的技巧常常让我重新思考我的代码并且工作稍微努力 - 但结果总是更易读/可维护。
If you are just a single programmer (Not on a team) I'd advise against Java, It doesn't do neat tricks and you won't see cool yearly feature updates--and it is fairly slow to program in (It moves a lot of time catching and fixing bugs into time spent coding, frustrating people with it's strict rules (One of the biggest advantages of the language IMO)
如果你只是一个程序员(不在一个团队中),我会建议不要使用Java,它不会做很好的技巧,你也不会看到很酷的年度功能更新 - 而且编程速度相当慢(它移动很多时候将错误捕获并修复到编码所花费的时间,用严格的规则来挫败人们(IMO语言的最大优势之一)
If you want something javaish try Scala instead. If you are "Forced" to learn it because of a classroom decision then you might want to attempt to appreciate it from the "team" point of view and with the mindset that you won't be forced to use it in the future.
如果你想要一些javaish尝试Scala而不是。如果你因为课堂决定而“*”去学习它,那么你可能想要尝试从“团队”的角度来理解它,以及你将来不会*使用它的心态。
#4
5
They might have wanted to remove a possible difference in semantics between the simple for and the enhanced for.
他们可能想要删除simple for和enhanced for之间可能存在的语义差异。
If you had, say, a regular for loop:
如果你有一个常规for循环:
int i;
for (i=0; i<4; i++)
;
then if you let the loop execute normally, you get that i==4
after the loop, which is not valid for the iteration variable.
那么如果你让循环正常执行,你会在循环之后得到i == 4,这对迭代变量无效。
What then, if you could have:
然后,如果你可以:
int i;
for (i : myArray)
;
I suppose from an implementation standpoint, it would be easiest if at the end i
were equal to the last element in the array. But should it behave like that or should there be some invalid value, and if so, what could that be? What if you break out of the last iteration?
我想从实现的角度来看,如果最后我等于数组中的最后一个元素,那将是最简单的。但是它应该表现得那样还是应该有一些无效的价值,如果是这样,那会是什么呢?如果你突破上一次迭代怎么办?
Another possibility is that it makes it more clear what that loop is about and what the element type of the collection is. By contrast, the simple for is a "legacy" construct in some sense, so they couldn't have applied a similar logic without "breaking" it or limiting its flexibility.
另一种可能性是它更清楚地说明了循环是什么以及集合的元素类型是什么。相比之下,简单的是某种意义上的“遗留”构造,因此它们不能在不“破坏”它或限制其灵活性的情况下应用类似的逻辑。
I'm obviously speculating, and it could turn out to have just been a random design choice.
我显然在猜测,它可能只是一个随机的设计选择。
#5
3
Maybe because in this way, it guarantees that state
will be empty and has no initial value assigned to it.
也许是因为以这种方式,它保证状态为空并且没有分配给它的初始值。