Java 8 Lambda语法更改

use*_*960 4 java lambda compiler-errors java-8

我遇到了一个问题,其中Lambda的允许语法在java编译器的1.8.0_05和1.8.0_20(beta)版本之间发生了变化.

例:

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")));
    }
}
Run Code Online (Sandbox Code Playgroud)

我想知道的 - 最后一个例子是有效的Lambda表达式吗?他们刚刚收紧了编译器验证?或者最新的1.8编译器中是否有错误?

最新编译器打印的错误是:

/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
Run Code Online (Sandbox Code Playgroud)

编辑(因为我似乎无法在回复中格式化评论):

setOnAction方法的实现是:

public final void setOnAction(EventHandler<ActionEvent> value) {
    onActionProperty().set( value);
}
Run Code Online (Sandbox Code Playgroud)

和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);
}
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 14

在Java编程语言中,方法调用表达式是一个表达式语句,一种可以出现在需要表达式或需要语句的地方的构造.

因此,即使方法返回,您也可以使用简化表达式表单param -> expression作为用例.由于此处预期的函数签名是,包含单个方法调用的lambda表达式对此上下文有效.e -> System.out.println("hi")void<T extends Event> T -> voidvoid

当您尝试在需要表达式的其他上下文中使用表达式语句时,情况会发生变化.比较JLS§15.1:

当且仅当它是调用不返回值的方法的方法调用(第15.12节)时,表达式才表示什么,即声明为void的方法(第8.4节).这样的表达式只能用作表达式语句(§14.8),因为表达式可以出现的每个其他上下文都需要表达式来表示某些东西.

正式应用这个规则,即使简单地在它周围放置括号(System.out.println("hi"))也是无效的,因为这是一个复合表达式,试图使用void在需要"真实表达式"(返回值)的上下文中声明的方法的方法调用.

因此使用无效表达式的lambda表达式也无效mi.setOnAction(e -> (System.out.println("hi")));.该消息有点误导.似乎编译器关注的是表单的表达式( whatever )是非语句表达式,因此在void上下文中无效.但是,报告将void方法调用放在圆括号中的初始错误会更有用.

你不能把规则( … )围绕一个void方法调用并没有改变,所以错误是老版本编译程序接受这种语法,这似乎已经固定现在.

  • 我认为,它与[本期](http://stackoverflow.com/q/23430854/2711488)有关[已在8u20-b13修复](http://download.java.net/jdk8u20/changes /jdk8u20-b13.html)(参见"应始终使用lambda body结构来消除重载决策的歧义") (2认同)