Java 8 Lambda syntax change

I ran into a problem when the allowed Lambda syntax changed between versions 1.8.0_05 and 1.8.0_20 (beta) of the java compiler.

Example:

package scratch; import javafx.scene.control.MenuItem; public class Test { public void test() { MenuItem mi = new MenuItem(); //This compiles anywhere mi.setOnAction(e -> System.out.println("hi")); //as does this mi.setOnAction(e -> {System.out.println("hi");}); //This doesn't on build 1.8.0_20-ea-b13 - but does on build 1.8.0_05-b13 mi.setOnAction(e -> (System.out.println("hi"))); } } 

What would I like to know - the last example of a valid Lambda expression? And did they just tighten the compiler check? Or is there an error in the latest 1.8 compiler?

Error printed by the latest compiler:

 /scratch/src/scratch/Test.java:18: error: method setOnAction in class MenuItem cannot be applied to given types; mi.setOnAction(e -> (System.out.println("hi"))); ^ required: EventHandler<ActionEvent> found: (e)->(Syst[...]hi")) reason: argument mismatch; bad return type in lambda expression missing return value 1 error 

Edit (since I cannot format comments in the answers):

Implementation of the setOnAction method:

 public final void setOnAction(EventHandler<ActionEvent> value) { onActionProperty().set( value); } 

And EventHandler:

 @FunctionalInterface public interface EventHandler<T extends Event> extends EventListener { /** * Invoked when a specific event of the type for which this handler is * registered happens. * * @param event the event which occurred */ void handle(T event); } 
+4
java lambda java-8 compiler-errors
Jun 10 '14 at 16:30
source share
1 answer

In the Java programming language, a method invocation expression is a Statement Statement , a construct that can appear in both places where an expression is required or where an instruction is required.

Therefore, you can use the simplified form of the expression param -> expression for the case of using e -> System.out.println("hi") , even if the method returns void . Since the expected signature function here is <T extends Event> T -> void , your lambda expression containing one call to the void method is valid for this context.

Things change when you try to use an Expression expression in a different context where the expression is required. Compare JLS ยง15.1 :

An expression does not mean anything if and only if it is a method call (ยง15.12) that calls a method that does not return a value, that is, a method declared void (ยง8.4). Such an expression can only be used as an expression (ยง14.8), because any other context in which the expression can be displayed requires an expression to denote something.

Applying this rule formally, even just putting curly braces around it, as in (System.out.println("hi")) , is invalid because it is a compound expression trying to use the method call of the declared void method in a context where "real expression "(return value).

And so the lambda expression using an invalid expression like in mi.setOnAction(e -> (System.out.println("hi"))); can not is also valid. The message is a bit misleading. It seems that the compiler focuses on the fact that the form expression ( whatever ) is an expression without an expression and therefore cannot be valid in the void context. However, reporting the original error placing the void method call in parentheses would be more useful.

The rule that you cannot put ( โ€ฆ ) around calling the void method has not changed, so the error was older than the compiler accepting this syntax, which seems to be fixed.

+14
Jun 10 '14 at 17:27
source share



All Articles