地图上的流不会保存.map更改

时间:2018-01-16 13:54:50

标签: java dictionary java-stream

有人可以解释一下为什么第一个代码示例没有保存我在地图上使用.map所做的更改,但是第二个代码示例呢?

第一个代码示例:

stringIntegerMap.entrySet().stream()
            .map(element -> element.setValue(100));

第二个代码示例:

        stringIntegerMap.entrySet().stream()
            .map(element -> element.setValue(100))
            .forEach(System.out::println);

另外,为什么第二个代码示例只打印值而不是整个元素(键+值)?

2 个答案:

答案 0 :(得分:7)

您的流操作是惰性评估的。

如果您不调用forEach(或collect等)等终端操作,则实际上不会发生流式传输,因此您的setValue不会被执行。

请注意,通常建议您修改正在流式传输的集合/地图。

最后,Map.Entry#setValue的API为here。 您会注意到该方法返回:

  

与条目

对应的旧值

因此,当您执行映射操作时,生成的流包含值。

某些来源here(搜索"流操作和流水线"以及有关"非干扰&#34的部分可能有所帮助)。

答案 1 :(得分:1)

Streams由源,中间操作和终端操作组成。

终端操作通过从源中懒洋洋地收集元素,然后应用中间操作并最终执行终端操作来开始管道处理。

Stream.map是一个中间操作,而Stream.forEach是终端。因此,在您的第一个代码段中,管道处理永远不会启动(因此中间操作永远不会执行),因为没有终端操作。在第二个片段中使用forEach时,将处理所有管道。

请查看java.util.stream package文档,其中包含有关流的大量信息以及如何正确使用它们(即您不应在中间或最终操作中修改流的来源,例如您'在Stream.map)。

修改

关于你的最后一个问题:

  

为什么第二个代码示例只打印值而不是整个元素(键+值)?

Mena's answer解释得很好:Map.Entry.setValue不仅为条目设置了给定值,还返回旧值。当您在Map.Entry.setValue中间操作中的lambda表达式中使用Stream.map时,实际上是在将流的每个Map.Entry元素转换为设置新值之前的值。因此,到达Stream.forEach的是地图的旧值,而地图则通过Map.Entry.setValue生成的副作用设置新值。