Ответ 1
Лучший способ сделать это с помощью потоков - использовать reduce
:
// make a transformer that combines all of them as one
Transformer combinedTransformer =
// the stream of transformers
transformers.stream()
// combine all the transformers into one
.reduce(
// apply each of the transformers in turn
(t1, t2) -> x -> t2.apply(t1.apply(x)))
);
// the stream of strings
strings.stream()
// transform each string with the combined transformer
.map(combinedTranformer::apply);
Конечно, это предполагает, что transformers
непусто; если есть вероятность, что он пуст, то достаточно просто использовать перегрузку с двумя аргументами reduce
вместо этого, например, (это предполагает, что Tranformer
является функциональным интерфейсом):
// make a transformer that combines all of them as one
Transformer combinedTransformer =
// the stream of transformers
transformers.stream()
// combine all the transformers into one
.reduce(
// the no-op transformer
x -> x,
// apply each of the transformers in turn
(t1, t2) -> x -> t2.apply(t1.apply(x)))
);
// the stream of strings
strings.stream()
// transform each string with the combined transformer
.map(combinedTranformer::apply);
Причина, по которой вы получили ошибку компилятора, заключается в том, что, как говорит ошибка, внешние переменные, используемые в выражении лямбда, должны быть эффективно окончательными; то есть объявить их final
(если они еще не установлены) не должны изменять значение программы или изменять, компилируется она или нет. Поэтому использование измененного назначения в лямбда, как правило, запрещено, и с полным основанием: мутация прикручивает распараллеливание, и одна из основных причин, которые lambdas были включены в Java 8, заключалась в том, чтобы упростить параллельное программирование.
Вообще говоря, всякий раз, когда вы хотите каким-то образом "подвести итоги", reduce
(в любой из трех своих перегрузок) - это ваш метод go-to. Изучение того, как использовать map
, filter
, reduce
и flatMap
, очень важно при работе с Stream
s.