比Stream.peek()更好的方法

“peek”主要用于调试。 如果我想在流的中间调用流上的方法,这会改变流对象的状态。

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

我可以:

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

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

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

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

最终编辑:我接受了@Holger的回答。 不能期望Stream.peek处理Stream上的所有元素,因为它不是终端操作。 map 。 即使您可能已经使用某些内容来终止您的流,这些内容可以保证它将处理所有操作,但您不应该编写希望每个用户都这样做的代码。 因此,要进行处理,您应该在Collection上使用forEach ,然后根据需要再次开始流式传输。

您过度使用方法引用。 Test::new的简单性是不值得的,如果它使你的其他流使用复杂化。

一个明确的解决方案是:

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

还是好多了

 Stream.of("Karl", "Jill", "Jack").map(first -> new Test(first, "Doe")) … 

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

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

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

唯一的方法是:

 .map(token -> {Test t = new Test(token); token.setLastname("joe"); return t;}) 

并非在每种情况下,为您要实现的目标定义新方法或构造函数都是有意义的。 您可以创建一个工具类Functions ,具有以下function:

 public static  Function of(Function function){ return function; } public static  Function peek(Consumer peeker){ return t -> { peeker.accept(t); return t; }; } 

然后你可以像这样使用它们:

 Stream.of("Karl", "Jill", "Jack").map(Functions.of(Test::new).andThen(Functions.peek(t -> t.setLastName("Doe")))); 

通过映射(应该是副作用免费),通过简单地为每个元素设置姓氏,不应该打扰流。 因此,我直接将它编写到本例中的构造函数中。