So, finally making a relatively large jump from Java 6 to Java 8, I've read up a fair amount of Java 8 Streams API. Unfortunately, almost all the examples that have been asked are almost close to what I'm trying to figure out how to do, but not close enough.
What I have is
final List<Function<? super Double, Double>> myList = generateList();
final double myVal = calculate(10);
private double calculate(double val) {
for (Function<? super Double, Double> function : this.myList) {
val += function.apply(val);
}
return val;
}
Now, I've come to understand I could do something similar with .stream().forEach()
, but that only applies the foreach and streams require final variables. I've tried to explore a bit with DoubleStream
to get a sum()
, but I'd need to re-apply the current sum to each Function
and add that sum to the next function, as the code example above shows.
Is this possible with pure Stream API?
Edit: So after testing with the reduce()
area, I ran a simple test on the time it takes to perform this type of calculation and the results aren't in favor of streams. Here's an example https://gist.github.com/gabizou/33f616c08bde5ab97e56. Included are the log outputs from the fairly basic test.
You can use the stream API to compose a function out of your list of functions.
static List<Function<? super Double, Double>> myList
= Arrays.asList(d -> d + 4, d -> d * 2, d -> d - 3);
static Function<Double, Double> total=myList.stream()
.map(f -> (Function<Double, Double>) d -> d + f.apply(d))
.reduce(Function::andThen).orElse(Function.identity());
static double calculate(double val) {
return total.apply(val);
}
public static void main(String[] args) {
System.out.println(calculate(10));
}
The stream operation which produces the composed function does not have the associativity problem and could in theory even run in parallel (though there is no benefit here) while the result is a single function which is per se sequential and never dissolved into parts which would need to be associative.
Yes, you can use a stream solution, by performing a reduction:
private double calculate(double val) {
return myList.stream().reduce(val, (d, f) -> d + f.apply(d), (a, b) -> a + b);
}
A reduction takes each element and aggregates (reduces) it to one value. There are 3 flavours of the reduce()
method - the one used here does the trick.
Some test code:
static Function<? super Double, Double> a = (d) -> d + 4;
static Function<? super Double, Double> b = (d) -> d * 2;
static Function<? super Double, Double> c = (d) -> d - 3;
static List<Function<? super Double, Double>> myList = Arrays.asList(a, b, c);
static double calculate(double val) {
return myList.stream().reduce(val, (d, f) -> d + f.apply(d), (a, b) -> a + b);
}
public static void main(String[] args) {
System.out.println(calculate(10));
}
Output:
141.0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With