Why can't this Java lambda compile?

The following Java code does not compile:

@FunctionalInterface private interface BiConsumer<A, B> { void accept(A a, B b); } private static void takeBiConsumer(BiConsumer<String, String> bc) { } public static void main(String[] args) { takeBiConsumer((String s1, String s2) -> new String("hi")); // OK takeBiConsumer((String s1, String s2) -> "hi"); // Error } 

Compiler Reports:

 Error:(31, 58) java: incompatible types: bad return type in lambda expression java.lang.String cannot be converted to void 

It is strange that a line labeled “OK” compiles fine, but a line labeled “Error” fails. They seem almost identical.

+81
java lambda java-8 compiler-errors void
Mar 25 '15 at 17:05
source share
4 answers

Your lambda should be congruent with BiConsumer<String, String> . If you are referencing JLS # 15.27.3 (Lambda Type) :

A lambda expression is congruent with a functional type, if all is true:

  • [...]
  • If the result of the function type is invalid, the lambda body is an operator expression (§14.8) or a block compatible with void.

So lambda should be an operator expression or block compatible with void:

+98
Mar 25 '15 at 17:51
source share

Basically, new String("hi") is an executable piece of code that actually does something (it creates a new line and then returns it). The return value can be ignored, and new String("hi") can still be used in lambda void-return to create a new string.

However, "hi" is just a constant that does nothing on its own. The only sensible thing related to this in the lambda body is to bring it back. But the lambda method would have to have a return type of String or Object , but it returns void , therefore, the String cannot be casted to void error String cannot be casted to void .

+42
Mar 25 '15 at 17:30
source share

The first case is normal, because you call the "special" method (constructor), and you actually do not accept the created object. To make this clearer, I will put optional curly braces in your lambdas:

 takeBiConsumer((String s1, String s2) -> {new String("hi");}); // OK takeBiConsumer((String s1, String s2) -> {"hi"}); // Error 

And more clearly, I will translate this into an older notation:

 takeBiConsumer(new BiConsumer<String, String>(String s1, String s2) { public void accept(String s, String s2) { new String("hi"); // OK } }); takeBiConsumer(new BiConsumer<String, String>(String s1, String s2) { public void accept(String s, String s2) { "hi"; // Here, the compiler will attempt to add a "return" // keyword before the "hi", but then it will fail // with "compiler error ... bla bla ... // java.lang.String cannot be converted to void" } }); 

In the first case, you are executing the constructor, but you are NOT returning the created object, in the second case, you are trying to return a String value, but your method in your BiConsumer interface returns void, so the compiler is an error.

+21
Mar 25 '15 at 17:30
source share

JLS indicates that

If the result of the function type is invalid, the lambda body is either an expression of an expression (§14.8) or a block compatible with void.

Now let's see that in detail,

Since your takeBiConsumer method is of type void, the receiving lambda new String("hi") will interpret it as a block, for example

 { new String("hi"); } 

which is valid in the void, so the first case compiles.

However, in the case where lambda -> "hi" , a block like

 { "hi"; } 

Invalid syntax in java. Therefore, the only thing you need to do with hello is to try and get it back.

 { return "hi"; } 

which is invalid in the void and explains the error message

 incompatible types: bad return type in lambda expression java.lang.String cannot be converted to void 

For a better understanding, note that if you change the type of takeBiConsumer to String, it will be valid -> "hi" because it will just try to directly return the string.




Please note that at first I made a mistake that the error was caused by the fact that lambda is in the wrong call context, so I shared this opportunity with the community:

JLS 15.27

This is a compile-time error if the lambda expression appears in a program in a place other than the destination context (§5.2), the call context (§5.3), or the casting context (§5.5).

However, in our case, we are in the context of a call that is correct.

+11
Mar 25 '15 at 17:11
source share



All Articles