我对java8流中map()
和forEach()
方法之间的区别感到困惑。例如,
List<String> strings = Lists.newArrayList("1", "2");
Map<String, String> map = Maps.newHashMap();
strings.stream().map(s->map.put(s, s));
System.out.println(map);
我在这里得到了空输出,但如果我将地图更改为forEach()
就像
List<String> strings = Lists.newArrayList("1", "2");
Map<String, String> map = Maps.newHashMap();
strings.stream().forEach(s->map.put(s, s));
System.out.println(map);
我可以
{1 = 1,2 = 2}
为什么它没有运行map()
方法?它们之间有什么区别?
答案 0 :(得分:21)
strings.stream().map(s->map.put(s, s));
不执行任何操作,因为在执行终端操作之前不会处理流管道。因此Map
仍为空。
向流管道添加终端操作将导致终端操作所需的map.put(s, s)
的每个元素执行Stream
(某些终端操作只需要一个元素,而其他元素需要所有元素) Stream
)。
另一方面,第二个流管道:
strings.stream().forEach(s->map.put(s, s));
以终端操作结束 - forEach
- 为Stream
的每个元素执行。
尽管如此,两个片段都在滥用Stream
。要根据Collection
的内容填充Map
或Stream
,您应该使用collect()
,这可以创建Map
或{ {1}}然后根据自己的喜好填充它。 Collection
和forEach
有不同的目的。
例如,要创建map
:
Map
答案 1 :(得分:7)
区别在于:
forEach()
的想法是对基础集合的每个元素“起作用”(通过具有副作用)而map()
是关于在每个对象上应用方法并将其结果放入新流这也是您的stream().map()
不会产生某些结果的原因 - 因为您抛出远离map()
来电创建的新流!
从这个意义上说,这两种方法的签名告诉你:
void forEach(BiConsumer<? super K,? super V> action)
对此地图中的每个条目执行给定操作,直到处理完所有条目
与
<R> Stream<R> map(Function<? super T,? extends R> mapper)
返回一个流,该流包含将给定函数应用于此流的元素的结果。
并且为了记录:只有map()
是流方法 - 对于流和集合/ Iterables都存在forEach()
。
答案 2 :(得分:0)
Stream
的每个实例方法的文档都说明该方法是中间操作还是终端操作。只有终端操作才会导致对流进行评估。除非下游终端操作需要,否则可以不执行中间操作。
这可以提高效率,尤其是当终端操作是短路操作时,例如findAny()
。在找到匹配元素之后,不需要为其他元素执行具有复杂中间操作集的管道。
在您的情况下,forEach()
是终端操作;它导致管道被执行。 map()
是一个中间操作;除非下游终端操作要求,否则它不必做任何事情。
答案 3 :(得分:-1)
你应该使用
stream().collect(Collectors.toMap(s -> s,s -> s)
...或其他内容,而不是stream().map(...)