Collection shouldn't be updated in lambda explanation
Sometimes I see these kind of code.
List<X> list = new ArrayList<>(); /*AnyCollection*/.forEach() .map(t -> list.add(t.getXXXX()));
I think it's bad code.
It's not thread safe
If you use parallel stream on above code...
List<X> list = new ArrayList<>(); /*AnyCollection*/.forEach().parallelStream() .map(x -> list.add(x.getXXXX()));
Of course, you can avoid this trouble if you don't use parallel stream.
However, there is no assuarance that nobody change this part to parallel in the future.
It's not "Function"
Lambda explanations accept only final (or actually final) variable from out of lambda. So any variables doesn't accept new value.*2
On the other hand, "update" isn't restricted like "add to list" or setter.
However, even it's not restricted, we shouldn't do any update against variable, which is defined out of lambda.
Idiom for making collection is existing
This is most common way to make list.
List<X> list = /*AnyCollection*/.stream() //parallel stream can be used .map(X::getXXXX) .collect(Collector.toList());
This format shows clearly that you want to make list better than previous sample.
Finally, forEach can use for just output
If you keep "rule that you cannot update any external value", only output, like logging, will be the role of forEach.
Then... I think you should avoid using forEach on Java as much as possible.