Collection.stream().forEach() 和 Collection.forEach() 之间有什么区别?
我知道,使用 ,我可以使用链操作,如或使用并行流。但是,如果我需要执行小操作(例如,打印列表的元素),它们之间有什么区别?.stream()
.filter()
collection.stream().forEach(System.out::println);
collection.forEach(System.out::println);
我知道,使用 ,我可以使用链操作,如或使用并行流。但是,如果我需要执行小操作(例如,打印列表的元素),它们之间有什么区别?.stream()
.filter()
collection.stream().forEach(System.out::println);
collection.forEach(System.out::println);
对于图示的简单情况,它们大多是相同的。但是,存在许多可能很重要的细微差异。
一个问题是订购。使用 时,顺序是未定义的。它不太可能发生在顺序流中,它仍然在以某种任意顺序执行的规范范围内。这在并行流中经常发生。相反, 始终按照 的迭代顺序执行,如果指定了一个。Stream.forEach
Stream.forEach
Iterable.forEach
Iterable
另一个问题是副作用。中指定的操作必须是非干扰的。(请参阅 java.util.stream 包文档。 可能具有较少的限制。对于 中的集合,通常会使用该集合,其中大多数被设计为快速失败,如果集合在迭代过程中被结构修改,则会抛出。但是,在迭代期间允许进行非结构化的修改。例如,ArrayList 类文档说“仅仅设置元素的值不是结构修改”。因此,允许的操作在基础中设置值而不会出现问题。Stream.forEach
Iterable.forEach
java.util
Iterable.forEach
Iterator
ConcurrentModificationException
ArrayList.forEach
ArrayList
并发集合再次不同。它们不是快速失败,而是设计为弱一致性。完整的定义位于该链接处。不过,请简要考虑一下 。传递给其方法的操作允许修改基础 deque,甚至在结构上,并且永远不会被抛出。但是,发生的修改在此迭代中可能可见,也可能不可见。(因此“弱”一致性。ConcurrentLinkedDeque
forEach
ConcurrentModificationException
如果正在迭代同步的集合,则还可以看到另一个差异。在此类集合上,获取集合的锁一次,并在对 action 方法的所有调用中保持该锁。该调用使用集合的拆分器,该拆分器不锁定,并且依赖于流行的不干扰规则。支持流的集合可以在迭代期间进行修改,如果是,则可能导致或不一致的行为。Iterable.forEach
Iterable.forEach
Stream.forEach
ConcurrentModificationException
这个答案与循环的各种实现的性能有关。它只与经常被调用的循环(如数百万个调用)稍微相关。在大多数情况下,循环的内容将是迄今为止最昂贵的元素。对于您经常循环的情况,这可能仍然很有趣。
您应该在目标系统下重复此测试,因为这是特定于实现的(完整的源代码)。
我在一台快速的Linux机器上运行openjdk版本1.8.0_111。
我写了一个测试,使用这个代码在List上循环10 ^ 6次,这些代码的大小不同(10 ^ 0 ->10 ^ 5个条目)。integers
结果如下,最快的方法因列表中的条目数量而异。
但是,在最坏的情况下,循环超过10 ^ 5个条目10 ^ 6次对于表现最差的人来说需要100秒,因此其他考虑因素在几乎所有情况下都更为重要。
public int outside = 0;
private void iteratorForEach(List<Integer> integers) {
integers.forEach((ii) -> {
outside = ii*ii;
});
}
private void forEach(List<Integer> integers) {
for(Integer next : integers) {
outside = next * next;
}
}
private void forCounter(List<Integer> integers) {
for(int ii = 0; ii < integers.size(); ii++) {
Integer next = integers.get(ii);
outside = next*next;
}
}
private void iteratorStream(List<Integer> integers) {
integers.stream().forEach((ii) -> {
outside = ii*ii;
});
}
以下是我的时间:毫秒/函数/列表中的条目数。每次运行 10^6 次循环。
1 10 100 1000 10000
iterator.forEach 27 116 959 8832 88958
for:each 53 171 1262 11164 111005
for with index 39 112 920 8577 89212
iterable.stream.forEach 255 324 1030 8519 88419
如果你重复这个实验,我发布了完整的源代码。请编辑此答案,并使用测试系统的符号添加您的结果。
使用 MacBook Pro、2.5 GHz Intel Core i7、16 GB、macOS 10.12.6:
1 10 100 1000 10000
iterator.forEach 27 106 1047 8516 88044
for:each 46 143 1182 10548 101925
for with index 49 145 887 7614 81130
iterable.stream.forEach 393 397 1108 8908 88361
Java 8 Hotspot VM - 3.4GHz Intel Xeon, 8 GB, Windows 10 Pro
1 10 100 1000 10000
iterator.forEach 30 115 928 8384 85911
for:each 40 125 1166 10804 108006
for with index 30 120 956 8247 81116
iterable.stream.forEach 260 237 1020 8401 84883
Java 11 Hotspot VM - 3.4GHz Intel Xeon,8 GB,Windows 10 Pro
(与上述机器相同,JDK版本不同)
1 10 100 1000 10000
iterator.forEach 20 104 940 8350 88918
for:each 50 140 991 8497 89873
for with index 37 140 945 8646 90402
iterable.stream.forEach 200 270 1054 8558 87449
Java 11 OpenJ9 VM - 3.4GHz Intel Xeon,8 GB,Windows 10 Pro
(与上述机器和JDK版本相同,VM不同)
1 10 100 1000 10000
iterator.forEach 211 475 3499 33631 336108
for:each 200 375 2793 27249 272590
for with index 384 467 2718 26036 261408
iterable.stream.forEach 515 714 3096 26320 262786
Java 8 Hotspot VM - 2.8GHz AMD, 64 GB, Windows Server 2016
1 10 100 1000 10000
iterator.forEach 95 192 2076 19269 198519
for:each 157 224 2492 25466 248494
for with index 140 368 2084 22294 207092
iterable.stream.forEach 946 687 2206 21697 238457
Java 11 Hotspot VM - 2.8GHz AMD,64 GB,Windows Server 2016
(与上述机器相同,JDK版本不同)
1 10 100 1000 10000
iterator.forEach 72 269 1972 23157 229445
for:each 192 376 2114 24389 233544
for with index 165 424 2123 20853 220356
iterable.stream.forEach 921 660 2194 23840 204817
Java 11 OpenJ9 VM - 2.8GHz AMD,64 GB,Windows Server 2016
(与上述机器和JDK版本相同,VM不同)
1 10 100 1000 10000
iterator.forEach 592 914 7232 59062 529497
for:each 477 1576 14706 129724 1190001
for with index 893 838 7265 74045 842927
iterable.stream.forEach 1359 1782 11869 104427 958584
您选择的 VM 实现也会有所不同 Hotspot/OpenJ9/等。