我在使用Stream.peek操作的另一个Stackoverflow question上出现的解决方案有效,但似乎仍然不对,因为它在Stream.peek
方法中改变了状态。
在研究(here和here)Stream.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似乎不允许它?
答案 0 :(得分:2)
你似乎做的事情看起来无害正如Brian Goetz在comment here中所述。
现在问题是,如果你在其中做副作用 - 你会发现这些副作用实际上发生 。所以,假设您想要改变某些对象的某些属性,如下所示:
myUserList.stream()
.peek(u -> u.upperCaseName())
.count()
在java-8中你的peek
确实会被调用,在9中 - 它不是 - 没有必要在这里调用peek
,因为无论如何都可以计算它的大小。
在同一条路径上,假设您的终端操作是短路操作,例如findFirst
或findAny
- 您不将处理所有元素源 - 您可能只通过管道获得其中一些。
如果您的peek
依赖于遭遇订单,即使您的终端操作不是短路操作,事情也可能变得更加奇怪。并行处理的中间操作没有遭遇顺序,而终端处理则没有。想象一下您可能面临的惊喜。