首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8 Lambda语法转换

Java 8 Lambda语法转换
EN

Stack Overflow用户
提问于 2014-06-10 16:30:53
回答 1查看 3K关注 0票数 4

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

示例:

代码语言:javascript
复制
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")));
    }
}

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

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

代码语言:javascript
复制
/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

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

setOnAction方法的实现是:

代码语言:javascript
复制
public final void setOnAction(EventHandler<ActionEvent> value) {
    onActionProperty().set( value);
}

和EventHandler:

代码语言:javascript
复制
@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);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-06-10 17:27:41

在Java语言中,方法调用表达式是一个表达式语句,它可以出现在两个位置,需要一个表达式或需要一个语句。

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

当您试图在需要表达式的不同上下文中使用表达式语句时,情况会发生变化。比较JLS§15.1

当调用不返回值的方法(§15.12),即声明为无效的方法(§8.4)时,表达式不表示任何值。这样的表达式只能用作表达式语句(第14.8节),因为表达式出现的每一个其他上下文都需要表达式来表示某事。

正式应用此规则,即使像在(System.out.println("hi"))中那样简单地设置大括号也是无效的,因为这是一个复合表达式,试图在需要“实际表达式”(返回值)的上下文中使用声明为void的方法调用。

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

不能将( … )放在void方法调用周围的规则没有改变,因此错误是较老的编译器接受了这个语法,而这个语法现在似乎已经修复了。

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24146285

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档