简体   繁体   English

Java 8 Lambda语法更改

[英]Java 8 Lambda Syntax change

I ran into an issue where the allowed syntax of a Lambda has changed between versions 1.8.0_05 and 1.8.0_20 (beta) of the java compiler. 我遇到了一个问题,其中Lambda的允许语法在java编译器的1.8.0_05和1.8.0_20(beta)版本之间发生了变化。

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 I would like to know - is the last example a valid Lambda expression? 我想知道的 - 最后一个例子是有效的Lambda表达式吗? And they have just tightened the compiler validation? 他们刚刚收紧了编译器验证? Or is there a bug in the latest 1.8 compiler? 或者最新的1.8编译器中是否有错误?

The error printed by the latest compiler is: 最新编译器打印的错误是:

/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 can't seem to format comments in replies): 编辑(因为我似乎无法在回复中格式化评论):

The implementation of the setOnAction method is: setOnAction方法的实现是:

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

And EventHandler: 和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);
}

In the Java programming language, a method invocation expression is an Expression Statement , a construct which can appear at both places, where an expression is required or where a statement is required. 在Java编程语言中,方法调用表达式是一个表达式语句 ,一种可以出现在需要表达式或需要语句的地方的构造。

Therefore you can use the simplified expression form param -> expression for the use case e -> System.out.println("hi") even if the method returns void . 因此,即使方法返回void也可以使用简化表达式形式param -> expression作为用例e -> System.out.println("hi") Since the function signature expected here is <T extends Event> T -> void , your lambda expression containing a single invocation of a void method is valid for this context. 由于此处预期的函数签名是<T extends Event> T -> void ,因此包含单个void方法调用的lambda表达式对此上下文有效。

Things change when you are trying to use the Expression Statement in a different context where an expression is required. 当您尝试在需要表达式的其他上下文中使用表达式语句时,情况会发生变化。 Compare JLS §15.1 : 比较JLS§15.1

An expression denotes nothing if and only if it is a method invocation (§15.12) that invokes a method that does not return a value, that is, a method declared void (§8.4). 当且仅当它是调用不返回值的方法的方法调用(第15.12节)时,表达式才表示什么,即声明为void的方法(第8.4节)。 Such an expression can be used only as an expression statement (§14.8), because every other context in which an expression can appear requires the expression to denote something. 这样的表达式只能用作表达式语句(§14.8),因为表达式可以出现的每个其他上下文都需要表达式来表示某些东西。

Applying this rule formally, even simply putting braces around it like in (System.out.println("hi")) is invalid as this is a compound expression trying to use the method invocation of a method declared void in a context where a “real expression” (returning a value) is required. 正式应用这个规则,即使简单地在(System.out.println("hi"))放置括号也是无效的,因为这是一个复合表达式,试图在上下文中使用方法调用声明为void的方法真实的表达“(返回一个值)是必需的。

And so the lambda expression using the invalid expression as in mi.setOnAction(e -> (System.out.println("hi"))); 所以使用无效表达式的lambda表达式如mi.setOnAction(e -> (System.out.println("hi"))); can't be valid either. 也无效。 The message is a bit misleading. 该消息有点误导。 It seems that the compiler focuses on the fact that an expression of the form ( whatever ) , is a non-statement expression and therefore can't be valid in a void context. 似乎编译器关注的是表单( whatever )表达式是非语句表达式,因此在void上下文中void However, reporting the initial error of putting a void method invocation in round braces would be more useful. 但是,报告在圆括号中放置void方法调用的初始错误会更有用。

The rule that you can't put ( … ) around a void method invocation didn't change, so the error was the older compiler accepting this syntax which seems to have been fixed now. 你不能把( … )围绕一个void方法调用的规则没有改变,所以错误是较旧的编译器接受这种语法,现在似乎已经修复了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM