我知道我们可以使用List.foreach
来遍历,我们也可以使用List.stream.foreach
来遍历。我不明白在Java8中遍历哪个更好。
请注意,尽管List.foreach
看起来类似于List.stream.foreach
,但它实际上并没有使用流式传输,因此它将在没有流式传输开销的情况下完成。
为了比较执行代码的复杂性,下面我将展示这两个结构如何工作的简化版本,通过删除验证逻辑来简化。
E、 g.在ArrayList
中,这实现为:
public void forEach(Consumer<? super E> action) {
for (int i = 0; i < size(); i++)
action.accept(get(i));
}
就是这样。真的就这么简单。
这需要多种方法:
// In Collection
default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
// In ArrayList
public Spliterator<E> spliterator() {
return new ArrayListSpliterator(0, -1, 0);
}
// In StreamSupport
public static <T> Stream<T> stream(Spliterator<T> spliterator, boolean parallel) {
return new ReferencePipeline.Head<>(spliterator,
StreamOpFlag.fromCharacteristics(spliterator),
parallel);
}
// In ReferencePipeline
public void forEach(Consumer<? super P_OUT> action) {
evaluate(ForEachOps.makeRef(action, false));
}
// In ForEachOps
public static <T> TerminalOp<T, Void> makeRef(Consumer<? super T> action,
boolean ordered) {
return new ForEachOp.OfRef<>(action, ordered);
}
// many method calls eventually leading to
// In ArrayListSpliterator
public void forEachRemaining(Consumer<? super E> action) {
for (int i = 0; i < size(); i++)
action.accept(get(i));
}
如您所见,它运行更多的代码,并创建至少 3 个对象。
for每次(消费者)
方法在Iterable
接口中声明,集合
,因此List
扩展了该接口。for每次(消费者)
的默认实现是:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
如您所见,默认实现只是在 for-each 循环中调用操作
。for-each 循环只是语法糖:
for (Iterator<?> iterator = iterable.iterator(); iterator.hasNext(); ) {
Object element = iterator.next();
// Do what you need to with element
}
除了您不能访问for-each循环中的Iterator
。
< code>Iterable的特定实现可能会改变它实际迭代其元素的方式(它可能使用也可能不使用< code >迭代器),但它几乎总是会归结到某个< code>for或< code>while循环。我说“几乎总是”是因为可能会涉及到某种类型的递归或链接。
现在,使用< code>List.stream()。当您只是尝试按顺序迭代< code>List时,forEach(Consumer)会创建一个不必要的< code>Stream对象。如果您确实需要以管道方式处理一组元素(比如映射、过滤、映射等等),那么您应该只使用流式API...).
因此,对于简单的迭代,在几乎所有情况下,使用 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.forEachOr的(消费者)
。
问题内容: 我了解使用,我可以使用类似链操作或使用并行流。但是,如果我需要执行小的操作(例如,打印列表的元素),它们之间有什么区别? 问题答案: 对于诸如所示的简单情况,它们基本上是相同的。但是,有许多细微的差异可能很重要。 一个问题是订购。使用,顺序不确定。顺序流不太可能发生,但仍可以按任意顺序执行。这确实在并行流中经常发生。相反,如果指定,则总是以的迭代顺序执行。 另一个问题是副作用。必须指定
我理解,使用,我可以使用类似的链操作,或者使用并行流。但是如果我需要执行小操作(例如,打印列表的元素),它们之间有什么区别呢?
这是一个例子:代码A: 另一个代码B可以这样使用: 两者有什么区别,有和没有?
在这篇文章中我将向你演示如何使用Java8中的foreach操作List和Map 1. Foreach操作Map 1.1 正常方式遍历Map Map<String, Integer> items = new HashMap<>(); items.put("A", 10); items.put("B", 20); items.put("C", 30); items.put("D", 40); ite
我正在从文件中读取值并获取列表。如下- 一旦我得到这个
产出: 请提供2个方法将产生不同输出的例子。