为什么要在java中的for-each循环内声明所需的variables
每个循环的通常forms是这样的:
for(Foo bar: bars){ bar.doThings(); }
但是,如果我想保留直到循环后,我不能使用每个循环:
Foo bar = null; // - Syntax error on token "bar", Identifier expected after this token for(bar: bars){ if(bar.condition()) break; } bar.doThings();
for循环获得上面提到的语法错误。
为什么是这样? 我对解决方法不感兴趣,只是对这个限制背后的考虑感到好奇。
相反,使用普通的for循环,variables可以在外部声明或者根本不声明…
int i = 1; for(;i<max;i++){ for(;;){ // Do things } }
这是一个很好的问题,我会很高兴看到一些深入的答案。 但是, 官方文件说:
这些缺点是由devise师所了解的,他们有意识地决定采用一个干净简单的结构来覆盖绝大多数情况。
绝大多数情况下是我的答案。
就个人而言,我认为Java中的foreach
循环只是标准迭代器循环的一个很好的语法。 因此,编译器会为结构创build迭代器,并使用variables来获取当前迭代的值。 为了确保variables已经被初始化,你需要为循环的范围声明它(并且我认为这可以防止variables被其他地方使用,例如在另一个线程中)。 因此,循环后不能使用variables。 但是,这只是我的意见,我会很高兴听到一个更了解它的人。 🙂
编辑这里有一篇关于Java中的foreach
循环的有趣文章 。
我分析了另一个编辑 (用jclasslib这些方法的字节码:
private static void testForEach(ArrayList<String> als) { for(String s: als) System.out.println(s); } private static void testIterator(ArrayList<String> als) { for(Iterator<String> is = als.iterator(); is.hasNext();) { String s = is.next(); System.out.println(s); } }
两种方法都由相同的字节码表示:
0 aload_0 1 invokevirtual #2 <java/util/ArrayList.iterator> 4 astore_1 5 aload_1 6 invokeinterface #3 <java/util/Iterator.hasNext> count 1 11 ifeq 34 (+23) 14 aload_1 15 invokeinterface #4 <java/util/Iterator.next> count 1 20 checkcast #5 <java/lang/String> 23 astore_2 24 getstatic #6 <java/lang/System.out> 27 aload_2 28 invokevirtual #7 <java/io/PrintStream.println> 31 goto 5 (-26) 34 return
区别在第一行,后一种方法使用invokevirtual #8
。 但是,两个调用都会调用Iterator
的相同方法。 所以, foreach
只不过是一个语法糖,编译器只是将它翻译成一个预定义的结构,就像文档中所说的那样。 这并不回答为什么它是这样的问题。 我认为在讨论的范围内,这可能是值得的。
我想他们只是想推广“良好实践”:从Java 语言指南 :
这些缺点是由devise师所了解的,他们有意识地决定采用一个干净简单的结构来覆盖绝大多数情况。
正如我们所知道的,你所要求的行为可以通过将for-each循环扩展到旧的基于迭代器的风格来模拟,可能他们只是认为它足够好。
在这种情况下遍历列表的方式是:
Foo bar = null; for(Iterator<Foo> barIterator = bars.iterator(); barIterator.hasNext();){ bar = barIterator.next(); // or whatever else you want to do ... }
不要迭代使用索引的列表,除非列表实现了RandomAccess!
增强的for循环只是这个迭代器方法的语法糖,它使循环的variables(here bar)保持在本地。 (尽量保持variables是一个好东西,一般来说)。
这个新语法的目的是为了美化,因为它没有真正添加任何新的Java。 我的猜测是,他们不允许你做的唯一原因的语法: 这不是美丽的! 🙂