java8流图在这里做了什么?

问题描述 投票:6回答:4

我对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()方法?他们之间有什么区别?

java sorting java-stream
4个回答
20
投票
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的每个元素执行。

也就是说,两个片段都在滥用Streams。为了根据Collection的内容填充MapStream,你应该使用collect(),它可以创建一个MapCollection并填充它,但你喜欢。 forEachmap有不同的目的。

例如,要创建Map

List<String> strings = Lists.newArrayList("1", "2");
Map<String, String> map = strings.stream()
                                 .collect(Collectors.toMap(Function.identity(),
                                                           Function.identity()));
System.out.println(map);

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()是流方法 - forEach()存在于两者,流和集合/ Iterables。


0
投票

Stream的每个实例方法的文档都说明该方法是中间操作还是终端操作。只有终端操作才会导致对流进行评估。除非下游终端操作需要,否则可以不执行中间操作。

这可以提高效率,特别是当终端操作是短路操作时,例如findAny()。在找到匹配元素之后,不需要为其他元素执行具有复杂中间操作集的管道。

在你的情况下,forEach()是一个终端操作;它导致管道被执行。 map()是一个中间操作;除非下游终端操作需要,否则它不需要做任何事情。


-1
投票

你应该用

stream().collect(Collectors.toMap(s -> s,s -> s)

...或者沿着这些方向的东西,而不是stream().map(...)


推荐问答