As per my understanding of java 8 lambda expressions, if we don't include code after "->" in curly braces that value will be returned implicitly. But in case of below example, forEach
method expects Consumer
and expression returns value but the compiler is not giving an error in Eclipse.
List<StringBuilder> messages = Arrays.asList(new StringBuilder(), new StringBuilder());
messages.stream().forEach(s-> s.append("helloworld"));//works fine
messages.stream().forEach((StringBuilder s)-> s.append("helloworld")); //works fine
messages.stream().forEach(s-> s); // doesn't work , Void methods cannot return a value
messages.stream().forEach(s-> s.toString()); // works fine
messages.stream().forEach(s-> {return s.append("helloworld");}); // doesn't work , Void methods cannot return a value
messages.stream().forEach((StringBuilder s)-> {return s.append("helloworld");}); // doesn't work , Void methods cannot return a value
s.append
returns StringBuilder
and s.toString()
returns String
but lambda treats it as void
.
What am I missing here? Why isn't the compiler giving an error when we invoke method on object?
Stream.forEach(Consumer)
takes a consumer which implements one methodi.e. it can't return anything.
If you want to return something you have to do something with the value returned.
You said
But that's not quite accurate. Rather, if you do not include curly braces, then, if a value could be be returned, then it will be returned implicitly. However, if a value should not be returned, because, for example, the functional interface method has a
void
return value, then the compiler will see that and not attempt to implicitly return anything.In this case, forEach accepts a Consumer, whose return type is
void
, which is why you are getting compile errors when you attempt to return a value from it explicitly.From JLS 15.27.3. Type of a Lambda Expression:
The highlighted sentence above means that any statement lambda expression (i.e. a lambda expression without a block) matches a functional interface whose single method's return type is
void
(such as theConsumer
functional interface required by theforEach
method).This explains why
s.append("helloworld")
&s.toString()
(your 1,2 & 4 examples) work fine as statement lambda expressions.examples 5 & 6 don't work, since those have block lambda bodies which are value-compatible lambda expressions. To be
void-compatible
, all the return statements must return nothing (i.e. justreturn;
).On the other hand, the following
void-compatible
block lambda bodies will pass compilation :Your 4th example -
messages.stream().forEach(s-> s);
doesn't work for the same reason the following method doesn't pass compilation :From
java.util.stream.Stream
, the signature offorEach
is:From
java.util.function.Consumer
, theaction
must implement the following method:In all your examples that don't work, you're returning a
T
, which doesn't match the return type ofvoid
.Because you're not trying to
return
something, the lambda's return type isvoid
, which matches the requiredConsumer
signature.The only possible type for
s -> s
isT -> T
, whereas(StringBuilder s) -> s.append()
could beStringBuilder -> ()
, which satisfies thevoid
requirement.