考虑:
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循环会是什么样子?
当前回答
Java中的for each循环使用底层迭代器机制。因此,它与以下内容相同:
Iterator<String> iterator = someList.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
System.out.println(item);
}
其他回答
nsayer的答案暗示了这一点,但值得注意的是,当“someList”是实现java.lang.Iterable的任何东西时,OP的for(..)语法都会起作用——它不必是列表,也不必是java.util的集合。因此,甚至您自己的类型也可以与此语法一起使用。
for (Iterator<String> i = someIterable.iterator(); i.hasNext();) {
String item = i.next();
System.out.println(item);
}
注意,如果需要使用i.remove();在循环中,或者以某种方式访问实际的迭代器,不能使用for(:)习惯用法,因为实际的迭代器只是推断出来的。
正如Denis Bueno所指出的,这段代码适用于实现Iterable接口的任何对象。
此外,如果for(:)习惯用法的右侧是数组而不是Iterable对象,则内部代码使用int索引计数器并检查array.length。请参阅Java语言规范。
Java“for each”循环构造将允许对两种类型的对象进行迭代:
T[](任何类型的数组)java.lang.Iterable<T>
Iterable<T>接口只有一个方法:Iterator<T>迭代器()。这对Collection<T>类型的对象有效,因为Collection<T<接口扩展了Iterable<T>。
正如许多好答案所说,如果一个对象想要使用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循环时会抛出异常。
Java for each循环(也称为增强的for循环)是for循环的简化版本。优点是编写的代码更少,管理的变量更少。缺点是无法控制步长值,也无法访问循环体中的循环索引。
当阶跃值是简单的1增量,并且您只需要访问当前循环元素时,最好使用它们。例如,如果需要在数组或集合中的每个元素上循环,而不在当前元素的前面或后面偷看。
没有循环初始化,没有布尔条件,步长值是隐式的,是一个简单的增量。这就是为什么它们被认为比常规for循环简单得多。
增强的for循环遵循以下执行顺序:
1) 环形体
2) 从步骤1开始重复,直到遍历了整个数组或集合
示例–整数数组
int [] intArray = {1, 3, 5, 7, 9};
for(int currentValue : intArray) {
System.out.println(currentValue);
}
currentValue变量保存在intArray数组中循环的当前值。请注意,没有显式的步长值——它总是以1为增量。
冒号可以被认为是“in”的意思。因此,增强的for循环声明声明:循环intArray并将当前数组int值存储在currentValue变量中。
输出:
1
3
5
7
9
示例–字符串数组
我们可以使用for each循环遍历字符串数组。循环声明声明:循环myStringsString数组并将当前String值存储在currentString变量中。
String [] myStrings = {
"alpha",
"beta",
"gamma",
"delta"
};
for(String currentString : myStrings) {
System.out.println(currentString);
}
输出:
alpha
beta
gamma
delta
示例–列表
增强的for循环还可以用于迭代java.util.List,如下所示:
List<String> myList = new ArrayList<String>();
myList.add("alpha");
myList.add("beta");
myList.add("gamma");
myList.add("delta");
for(String currentItem : myList) {
System.out.println(currentItem);
}
循环声明声明:循环myList List of Strings并将当前List值存储在currentItem变量中。
输出:
alpha
beta
gamma
delta
示例–集合
增强的for循环还可以用于迭代java.util.Set,如下所示:
Set<String> mySet = new HashSet<String>();
mySet.add("alpha");
mySet.add("alpha");
mySet.add("beta");
mySet.add("gamma");
mySet.add("gamma");
mySet.add("delta");
for(String currentItem : mySet) {
System.out.println(currentItem);
}
循环声明声明:循环mySet字符串集,并将当前Set值存储在currentItem变量中。注意,因为这是一个Set,所以不会存储重复的String值。
输出:
alpha
delta
beta
gamma
来源:Java中的循环–终极指南