Issue
I have a List<UnaryOperator<String>>
and need to map/transform a String by passing it through the list of operators. I have the following functional Java 11 code:
UnaryOperator<String> addA = (startString) -> startString + "a";
UnaryOperator<String> addB = (startString) -> startString + "b";
UnaryOperator<String> addc = (startString) -> startString + "c";
List<UnaryOperator<String>> operators = List.of(addA, addB, addc);
String concatenatedString =
operators
.stream()
.reduce(
"", // identity
(value, op) -> op.apply(value), // accumulator
(value1, value2) -> value1.concat(value2) // combiner
);
System.out.println(concatenatedString); // prints "abc" as expected.
The concern I have is the string concatenation is expressed in 2 places. First in each of the UnaryOperator
s and second in the combiner argument. Makes me wonder if there is a better way to do this?
Solution
You can use the advantage that UnaryUperator<T> extends Function<T, T>
and chain multiple calls of Function::andThen
to get a composed UnaryOperator<String>
of all within the list:
UnaryOperator<String> mergedUnaryOperators = operators.stream()
.reduce((l, r) -> (string) -> l.andThen(r).apply(string))
.orElseGet(UnaryOperator::identity);
String output = mergedUnaryOperators.apply(""); // results in "abc"
To have a clearer picture how does it work, this is called inside the reduce
method:
new BinaryOperator<UnaryOperator<String>>() {
@Override
public UnaryOperator<String> apply(UnaryOperator<String> l, UnaryOperator<String> r) {
return string -> l.andThen(r).apply(string);
}
}
Answered By - Nikolas Charalambidis
Answer Checked By - Gilberto Lyons (JavaFixing Admin)