终端操作以评估中间操作

时间:2019-03-21 11:36:13

标签: java java-8 java-stream

说我有一个字符串列表,我想将这些字符串用作流利的构建器的输入。

List<String> scripts;

//initialize list

ScriptRunnerBuilder scriptRunnerBuilder = new ScriptRunnerBuilder();

BiFunction<String,ScriptRunnerBuilder,ScriptRunnerBuilder> addScript = 
(script,builder) -> builer.addScript(script);

scriptRunnerBuilder = scripts.stream.map(script -> 
addScript.apply(script,scriptRunnerBuilder)).......

scriptRunnerBuilder.build();

我可以使用哪个终端操作,以便对列表中的所有元素调用addScript函数?

问题在于ScriptRunnerBuilder是不可变的,因此ScriptRunnerBuilder.addScript()返回一个新的ScriptRunnerBuilder对象,而不是修改现有对象-因此我不能只给我们一个foreach。

我的意图是携带addScript()调用的结果,并将其用作流中下一个元素的输入

3 个答案:

答案 0 :(得分:5)

最简单的方法应该是:

// create your builder
ScriptRunnerBuilder builder = new ScriptRunnerBuilder();

// add all scripts
scripts.forEach(script-> builder.addScript(script))

build results
scriptRunnerBuilder.build();

因为构建器聚合了所有数据,并且您已经在for lambda外部创建了数据,所以可以直接访问它。这将导致更少的代码和相同的结果。

或按照@Holger的建议:

scripts.forEach(builder::addScript);

答案 1 :(得分:2)

使用forEach代替map,并且不再分配流的结果

scripts.forEach(script -> addScript.apply(script,scriptRunnerBuilder));

答案 2 :(得分:1)

  

我可以使用reduce操作,但这是不必要的,因为我们不合并结果

合并正是您的工作。 您将List<String>ScriptRunnerBuilder的所有脚本组合在一起了吗?

我同意@Beri不带流的解决方案可能是最简单的。但是,reduce(identity, accumulator, combiner)方法也有一种方法,您无需在之前创建ScriptRunnerBuilder

ScriptRunnerBuilder builder = scripts.stream()
        .reduce(new ScriptRunnerBuilder(), ScriptRunnerBuilder::addScript, (b1, b2) -> b1);

查看更多:Why is a combiner needed for reduce method that converts type in java 8

更新要不依赖于combiner没有被顺序流调用并使其与并行流一起工作这一事实,您必须实现真正的combiner

如果您可以添加覆盖的方法addScript(ScriptRunnerBuilder otherBuilder),则reduce如下所示:

.reduce(new ScriptRunnerBuilder(), ScriptRunnerBuilder::addScript, 
        ScriptRunnerBuilder::addScript)