0%

stream and lambda(14) - 终止操作之 stream 遍历(forEach & forEachOrdered)

Stream 提供的遍历方法有两个,一个是 foreach,一个是 foreachOrdered。当然,foreach 方法在集合中也存在,相信大家在以前的编码过程中或多或少都有用到过。

方法定义

void forEach(Consumer<? super T> action);
void forEachOrdered(Consumer<? super T> action);

两个方法从使用上来讲都是一样的,具体区别是,在并行流遍历时,由于流元素是多线程在处理,foreach 无法保证处理的顺序,而 foreachOrdered 可以保证处理的顺序。

使用举例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public void foreachTest() {
List<String> strings = Arrays.asList("this", "is", "foreachTest");

System.out.println("原始顺序");
strings.forEach(s -> System.out.print(s + " "));

System.out.println("\n\n串行流的 foreach");
strings.stream().forEach(
s -> System.out.println(Thread.currentThread().getName() + ":" + s)
);

System.out.println("\n并行流的 foreach");
strings.parallelStream().forEach(
s -> System.out.println(Thread.currentThread().getName() + ":" + s)
);

System.out.println("\n串行流的 foreachOrdered");
strings.stream().forEachOrdered(
s -> System.out.println(Thread.currentThread().getName() + ":" + s)
);

System.out.println("\n并行流的 foreachOrdered");
strings.parallelStream().forEachOrdered(
s -> System.out.println(Thread.currentThread().getName() + ":" + s)
);
}

输出结果如下:

原始顺序
this is foreachTest

串行流的 foreach
main:this
main:is
main:foreachTest

并行流的 foreach
main:is
ForkJoinPool.commonPool-worker-2:foreachTest
ForkJoinPool.commonPool-worker-1:this

串行流的 foreachOrdered
main:this
main:is
main:foreachTest

并行流的 foreachOrdered
ForkJoinPool.commonPool-worker-3:this
main:is
main:foreachTest

可以看出,串行流时,两种方法的输出是一致,且顺序都是原始顺序,执行线程是主线程;并行流时,foreach 无法保证输出顺序,而 foreachOrdered 可以保证输出顺序,执行线程有些是线程池的。

总结

  • foreachforeachOrdered 在串行流处理时,结果是一样的。
  • 并行流时,foreach 处理的顺序有可能是乱序的,foreachOrdered 处理的顺序是按照流元素的顺序。
  • 并行流时,如果对处理顺序无要求,使用 foreachOrdered 效率会更高一些。