考虑:
List<String> someList = new ArrayList<String>();
// add "monkey", "donkey", "skeleton key" to someList
for (String item : someList) {
System.out.println(item);
}
如果不使用for each语法,等价的for循环会是什么样子?
考虑:
List<String> someList = new ArrayList<String>();
// add "monkey", "donkey", "skeleton key" to someList
for (String item : someList) {
System.out.println(item);
}
如果不使用for each语法,等价的for循环会是什么样子?
当前回答
代码应为:
import java.util.ArrayList;
import java.util.List;
public class ForLoopDemo {
public static void main(String[] args) {
List<String> someList = new ArrayList<String>();
someList.add("monkey");
someList.add("donkey");
someList.add("skeleton key");
// Iteration using For Each loop
System.out.println("Iteration using a For Each loop:");
for (String item : someList) {
System.out.println(item);
}
// Iteration using a normal For loop
System.out.println("\nIteration using normal For loop: ");
for (int index = 0; index < someList.size(); index++) {
System.out.println(someList.get(index));
}
}
}
其他回答
这里有一个答案,它不假定了解Java迭代器。它不太精确,但对教育有用。
在编程时,我们通常编写如下代码:
char[] grades = ....
for(int i = 0; i < grades.length; i++) { // for i goes from 0 to grades.length
System.out.print(grades[i]); // Print grades[i]
}
foreach语法允许以更自然、更少语法噪音的方式编写这种常见模式。
for(char grade : grades) { // foreach grade in grades
System.out.print(grade); // print that grade
}
此外,此语法对于不支持数组索引但实现Java Iterable接口的Lists或Set等对象有效。
如JLS中所定义的,每个循环的a可以有两种形式:
如果表达式类型是Iterable的子类型,则转换为:List<String>someList=newArrayList<String>();someList.add(“苹果”);someList.add(“球”);for(字符串项:someList){System.out.println(项);}//翻译为:for(Iterator<String>stringIterator=someList.iiterator();stringIterator.hasNext();){字符串项=stringIterator.next();System.out.println(项);}如果表达式必须具有数组类型T[],则:String[]someArray=新字符串[2];someArray[0]=“苹果”;someArray[1]=“球”;for(字符串项2:someArray){系统输出打印(第2项);}//翻译为:for(int i=0;i<someArray.length;i++){字符串item2=someArray[i];系统输出打印(第2项);}
Java8已经引入了一些流,这些流在适当大小的数据集中通常表现得更好。我们可以将它们用作:
someList.stream().forEach(System.out::println);
Arrays.stream(someArray).forEach(System.out::println);
正如许多好答案所说,如果一个对象想要使用for each循环,它必须实现Iterable接口。
我将发布一个简单的示例,并尝试以不同的方式解释for each循环的工作原理。
对于每个循环示例:
public class ForEachTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("111");
list.add("222");
for (String str : list) {
System.out.println(str);
}
}
}
然后,如果我们使用javap来反编译这个类,我们将得到这个字节码示例:
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: new #16 // class java/util/ArrayList
3: dup
4: invokespecial #18 // Method java/util/ArrayList."<init>":()V
7: astore_1
8: aload_1
9: ldc #19 // String 111
11: invokeinterface #21, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
16: pop
17: aload_1
18: ldc #27 // String 222
20: invokeinterface #21, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
25: pop
26: aload_1
27: invokeinterface #29, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
从示例的最后一行可以看到,编译器将在编译时自动将for每个关键字的使用转换为Iterator的使用。这可以解释为什么对象(它没有实现Iterable接口)在尝试使用for each循环时会抛出异常。
forEach的替代方案,以避免“for each”:
List<String> someList = new ArrayList<String>();
变体1(普通):
someList.stream().forEach(listItem -> {
System.out.println(listItem);
});
变体2(并行执行(更快)):
someList.parallelStream().forEach(listItem -> {
System.out.println(listItem);
});
它看起来像这样。非常粗糙。
for (Iterator<String> i = someList.iterator(); i.hasNext(); )
System.out.println(i.next());
Sun文档中对每一项都有很好的描述。