比Stream.peek()更好的方法

K.N*_*las 6 java lambda java-8

"peek"主要用于调试.如果我想在流的中间调用流上的方法,这会改变流对象的状态,该怎么办?

Stream.of("Karl", "Jill", "Jack").map(Test::new).peek(t->t.setLastName("Doe"));
Run Code Online (Sandbox Code Playgroud)

我可以:

Stream.of("Karl", "Jill", "Jack").map(Test::new).map(t->{t.setLastName("Doe"); return t;});
Run Code Online (Sandbox Code Playgroud)

但这看起来很难看.这是不应该做的事情还是有更好的方法来做到这一点?

编辑:forEach除了它是一个终端操作,然后你不能继续在流上工作.然后我会期望制作一个Collection,do forEach,然后再开始流式传输Collection.

编辑:map(Class::processingMethod)是我现在正在做的,但由于processingMethod简单地返回this,它似乎是对地图的误用.此外,它并不像业务逻辑那样真正地读取.

最终编辑:我接受了@Holger的回答.Stream.peek不能指望处理Stream上的所有元素,因为它不是终端操作.同样的道理map.即使您可能已经使用可以保证它将处理所有操作的内容终止了您的流,但您不应该编写希望每个用户都这样做的代码.因此,要进行处理,您应该使用forEacha Collection,然后Collection如果您愿意再次开始流式处理.

Hol*_*ger 9

您过度使用方法引用.Test::new如果它使您的其他流使用变得复杂,那么简单性就没有任何价值.

一个明确的解决方案是:

Stream.of("Karl", "Jill", "Jack")
      .map(first -> { Test t = new Test(first); t.setLastName("Doe"); return t; })
      …
Run Code Online (Sandbox Code Playgroud)

还是好多了

Stream.of("Karl", "Jill", "Jack").map(first -> new Test(first, "Doe")) …
Run Code Online (Sandbox Code Playgroud)

假设该类具有不那么遥远的构造函数接受这两个名称.

上面的代码解决了用例,其中操作操作本地构造的对象,因此仅当对象将被后续Stream操作使用时,操作才是相关的.对于其他情况,如果操作对Stream之外的对象产生副作用,滥用map几乎所有的缺点都peek在" 在Java流中解释,实际上只是用于调试?"

  • @Nicholas:对副作用滥用`map`与使用`peek`相提并论.它可能会工作,如果它被限制为像你的例子那样操纵本地创建的对象,但是然后,将创建和操作融合到一个步骤中,就像在我的回答中一样,会更加清晰.在所有其他情况下,滥用`map`几乎具有`peek`中所解释的所有缺点[在Java流中,实际上仅用于调试?](http://stackoverflow.com/a/33636377/2711488). (3认同)

Eug*_*ene 6

即使您使用两个参数创建另一个构造函数,也无法使用方法引用.

唯一的方法是:

.map(token -> {Test t = new Test(token); token.setLastname("joe"); return t;})
Run Code Online (Sandbox Code Playgroud)

  • 类*有一个带字符串的构造函数,但它是*first*name.添加另一个参数将是有用的(可能这样的构造函数甚至存在),但它不能与Stream中的这样一个简单的方法引用一起使用,因为该对象应该使用stream元素(名字)和常数(姓氏)`"Doe"`. (2认同)