Suppose I have a List<String>
and a List<Transfomer>
. I want to apply each transformer to each string in the list.
Using Java 8 lambdas, I can do this:
strings.stream().map(s -> {
for(Transformer t : transformers) {
s = t.apply(s);
}
return s;
}).forEach(System.out::println);
But I'd like to do something more like this, however it results in a compile time error:
strings.stream().map(s -> transformers.stream().forEach(t -> s = t.apply(s))).forEach(System.out::println);
I'm just starting to play with lambdas, so maybe I just don't have the syntax correctly.
The best way to do this with streams is to use
reduce
:Of course, this assumes that
transformers
is non-empty; if there is a possibility that it is empty, than it is simple enough to use the two-argument overload ofreduce
instead, like so (this assumesTranformer
is a functional interface):The reason you got a compiler error is that, as the error says, outside variables used in a lambda expression must be effectively final; that is, declaring them
final
(if they aren't already) must not change the meaning of the program, or change whether or not it compiles. Using a mutable assignment in a lambda is therefore generally forbidden, and with good reason: mutation screws up parallelization, and one of the major reasons lambdas were included in Java 8 was to allow easier parallel programming.Generally speaking, whenever you want to "sum up" results in some way,
reduce
(in any of its three overloads) is your go-to method. Learning how to usemap
,filter
,reduce
, andflatMap
effectively is very important when working withStream
s.Lambdas (just like local classes) cannot ever assign to captured local variables, whether from an outer lambda, or from an enclosing method. Captured local variables must be effectively final.