Терминальная операция для оценки промежуточной операции - PullRequest
1 голос
/ 21 марта 2019

Пусть говорит, что у меня есть список строк, и я хочу использовать эти строки в качестве входных данных для плавного компоновщика.

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 ]

5 голосов
/ 21 марта 2019

Проще всего это должно быть:

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

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

build results
scriptRunnerBuilder.build();

Поскольку компоновщик объединяет все данные, и вы создали их вне для каждой лямбды, вы можете получить к ней доступ напрямую.Это приведет к меньшему количеству кода и тому же результату.

Или, как предложил @Holger:

scripts.forEach(builder::addScript);
2 голосов
/ 21 марта 2019

Используйте forEach вместо map и больше не назначайте результат потока

scripts.forEach(script -> addScript.apply(script,scriptRunnerBuilder));
1 голос
/ 21 марта 2019

Я мог бы использовать операцию сокращения, но это не нужно, поскольку мы не объединяем результаты.

Объединение - это именно то, что вы делаете.Вы объединяете все сценарии от List<String> до ScriptRunnerBuilder не так ли?

Я согласен, что решение @ Beri без потока, вероятно, самое простое.Но также есть способ с reduce(identity, accumulator, combiner), при котором вам не нужно создавать ScriptRunnerBuilder до:

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

Подробнее: Зачем нужен объединительДля метода Reduce, который преобразует тип в Java 8

Обновление Чтобы не полагаться на тот факт, что combiner не вызывается для последовательного потока, и заставить его работать с параллельным потокомВы должны реализовать реальные combiner.

Если бы вы могли добавить переопределенный метод addScript(ScriptRunnerBuilder otherBuilder), тогда reduce будет выглядеть так:

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