考虑:

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只能应用于*Iterable类型的数组或对象。这个习惯用法是隐含的,因为它确实有迭代器支持。迭代器由程序员编程,通常使用整数索引或节点(取决于数据结构)来跟踪其位置。从理论上讲,它比常规的for循环慢,至少对于数组和列表等“线性”结构来说是这样,但它提供了更大的抽象性。

其他回答

在Java 8功能中,您可以使用以下功能:

List<String> messages = Arrays.asList("First", "Second", "Third");

void forTest(){
    messages.forEach(System.out::println);
}

输出

First
Second
Third

正如许多其他答案正确指出的那样,for each循环只是同一个旧for循环的语法糖,编译器将其转换为同一个老for循环。

javac(OpenJDK)有一个开关-XD printflat,它生成一个Java文件,去掉了所有语法糖。完整的命令如下所示:

javac -XD-printflat -d src/ MyFile.java

//-d is used to specify the directory for output java file

所以让我们去掉语法糖

为了回答这个问题,我创建了一个文件,并为每个文件编写了两个版本,一个带有数组,另一个带有列表。我的Java文件如下所示:

import java.util.*;

public class Temp{

    private static void forEachArray(){
        int[] arr = new int[]{1,2,3,4,5};
        for(int i: arr){
            System.out.print(i);
        }
    }

    private static void forEachList(){
        List<Integer> list = Arrays.asList(1,2,3,4,5);
        for(Integer i: list){
            System.out.print(i);
        }
    }
}

当我用上面的开关编译这个文件时,我得到了以下输出。

import java.util.*;

public class Temp {

    public Temp() {
        super();
    }

    private static void forEachArray() {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        for (/*synthetic*/ int[] arr$ = arr, len$ = arr$.length, i$ = 0; i$ < len$; ++i$) {
            int i = arr$[i$];
            {
                System.out.print(i);
            }
        }
    }

    private static void forEachList() {
        List list = Arrays.asList(new Integer[]{Integer.valueOf(1), Integer.valueOf(2), Integer.valueOf(3), Integer.valueOf(4), Integer.valueOf(5)});
        for (/*synthetic*/ Iterator i$ = list.iterator(); i$.hasNext(); ) {
            Integer i = (Integer)i$.next();
            {
                System.out.print(i);
            }
        }
    }
}

您可以看到,与其他语法糖(Autoboxing)一起,每个循环都被更改为简单循环。

如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);

还要注意,在原始问题中使用“foreach”方法确实有一些限制,例如在迭代过程中无法从列表中删除项目。

新的for循环更容易阅读,并且不需要单独的迭代器,但只有在只读迭代过程中才能真正使用。

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);
});