Stream.peek改变状态的可能副作用以及为什么不这样使用它

时间:2017-11-17 18:24:19

标签: java java-stream

我在使用Stream.peek操作的另一个Stackoverflow question上出现的解决方案有效,但似乎仍然不对,因为它在Stream.peek方法中改变了状态。

在研究(herehereStream.peek使用是否可以改变状态时,我仍然不完全相信Stream.peek不应该改变状态(包括作为Stream)的来源的集合状态。

以下是Javadoc所说的内容:

  

此方法主要用于支持调试,您希望在元素流经管道中的某个点时查看元素:

然后:

  

参数:action - 要对其执行的非干扰操作   元素从流中消耗。

     

表现良好的无干扰   流源,源可以在终端之前修改   操作开始,这些修改将反映在   覆盖的元素。从JDK集合返回的所有流,和   大多数其他JDK类都以这种方式表现良好。

似乎非干扰操作确实包括更改流中的收集状态。

以下是使用Stream.peek的代码。

Map< String, List<Test> > userTests = new HashMap<>();

Map< String, List<Test> > filtered  = userTests.entrySet().stream()
        .peek( e -> e.setValue( modifyListAndReturnIt( e.getValue() ) ) )
        .filter( e -> !e.getValue().isEmpty() ) //check if modified list in peek has been emptied
        .collect( Collectors.toMap(p -> p.getKey(), p -> p.getValue() ) );

    public static List<Test> modifyListAndReturnIt(List<Test> list){
        if (somecondition) list.clear();
        return list;
    }

1)上述代码可以有任何副作用吗?

2)为什么不以这种方式使用偷看。 Javadoc似乎不允许它?

1 个答案:

答案 0 :(得分:2)

你似乎做的事情看起来无害正如Brian Goetz在comment here中所述。

现在问题是,如果你在其中做副作用 - 你会发现这些副作用实际上发生 。所以,假设您想要改变某些对象的某些属性,如下所示:

myUserList.stream()
          .peek(u -> u.upperCaseName())
          .count()

在java-8中你的peek确实会被调用,在9中 - 它不是 - 没有必要在这里调用peek,因为无论如何都可以计算它的大小。

在同一条路径上,假设您的终端操作是短路操作,例如findFirstfindAny - 您将处理所有元素 - 您可能只通过管道获得其中一些。

如果您的peek依赖于遭遇订单,即使您的终端操作不是短路操作,事情也可能变得更加奇怪。并行处理的中间操作没有遭遇顺序,而终端处理则没有。想象一下您可能面临的惊喜。