首页 > 解决方案 > Java8容器`for each`和Stream`for each`有什么区别

问题描述

我知道我们可以List.foreach 用来遍历,我们也可以List.stream.foreach用来遍历。我不明白在 Java8 中遍历哪个更好。

标签: javajava-8iteration

解决方案


forEach(Consumer)方法在Iterable接口中声明Collection,因此List扩展。默认实现forEach(Consumer)是:

default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
        action.accept(t);
    }
}

如您所见,默认实现只是action在 for-each 循环中调用。for-each 循环只是语法糖:

for (Iterator<?> iterator = iterable.iterator(); iterator.hasNext(); ) {
    Object element = iterator.next();
    // Do what you need to with element
} 

Iterator除非您在 for-each 循环中无权访问。

的特定实现Iterable可能会改变它实际迭代其元素的方式(它可能使用也可能不使用 an Iterator),但它几乎总是归结为 some fororwhile循环。我说“几乎总是”是因为可能涉及某种类型的递归或链接。

现在,当您只是尝试按顺序迭代时, usingList.stream().forEach(Consumer)会创建一个不必要的对象。如果您确实需要以管道方式处理元素集合(例如映射、过滤、更多映射等),则应仅使用流 API。StreamList

因此,对于简单的迭代,几乎在所有情况下,使用List.stream().forEach(Consumer)的性能都比简单的调用低。List.forEach(Consumer)性能提升很可能可以忽略不计,但“优化”并不过分是一个足够简单的修复;特别是如果您一开始就没有犯“错误”。如果您不需要它们,请不要创建对象。

最好简单地使用 for-each 循环而不是forEach(Consumer)虽然。它比功能更强大的对应物更容易阅读。


编辑

正如 Holger 在评论中提到的,与以下Stream.forEach(Consumer)有很大的不同Iterable.forEach(Consumer):它不保证元素的相遇顺序。虽然接口的迭代顺序Iterable.forEach(Consumer)也没有定义Iterable,但可以通过扩展接口(如List)来定义。但是,在使用时,无论 的来源如何,Stream不能保证顺序。Stream

如果您希望在使用 a 时保证订单,Stream您必须使用Stream.forEachOrdered(Consumer).


推荐阅读