What is the equivalent of of Scala's great foldLeft
in Java 8?
I was tempted to think it was reduce
, but reduce has to return something of identical type to what it reduces on.
Example:
import java.util.List;
public class Foo {
// this method works pretty well
public int sum(List<Integer> numbers) {
return numbers.stream()
.reduce(0, (acc, n) -> (acc + n));
}
// this method makes the file not compile
public String concatenate(List<Character> chars) {
return chars.stream()
.reduce(new StringBuilder(""), (acc, c) -> acc.append(c)).toString();
}
}
The problem in the code above is the acc
umulator: new StringBuilder("")
Thus, could anyone point me to the proper equivalent of the foldLeft
/fix my code?
There is no equivalent of foldLeft
in Java 8's Stream API. As others noted, reduce(identity, accumulator, combiner)
comes close, but it's not equivalent with foldLeft
because it requires the resulting type B
to combine with itself and be associative (in other terms, be monoid-like), a property that not every type has.
There is also an enhancement request for this: add Stream.foldLeft() terminal operation
To see why reduce won't work, consider the following code, where you intend to execute a series of arithmetic operations starting with given number:
val arithOps = List(('+', 1), ('*', 4), ('-', 2), ('/', 5))
val fun: (Int, (Char, Int)) => Int = {
case (x, ('+', y)) => x + y
case (x, ('-', y)) => x - y
case (x, ('*', y)) => x * y
case (x, ('/', y)) => x / y
}
val number = 2
arithOps.foldLeft(number)(fun) // ((2 + 1) * 4 - 2) / 5
If you tried writing reduce(2, fun, combine)
, what combiner function could you pass that combines two numbers? Adding the two numbers together clearly does not solve it. Also, the value 2
is clearly not an identity element.
Note that no operation that requires a sequential execution can be expressed in terms of reduce
. foldLeft
is actually more generic than reduce
: you can implement reduce
with foldLeft
but you cannot implement foldLeft
with reduce
.