Java 的 lambda 语法的细分是什么? [英] What is the breakdown for Java's lambda syntax?

查看:24
本文介绍了Java 的 lambda 语法的细分是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请解释 Java 8 的 lambda 方法的语法.

Please explain the syntax for Java 8's lambda methods.

对于什么 lambda 函数有很多解释,但我找不到语法的详尽解释,而且我发现学习复制语法非常困难正确,因为我不明白为什么他们是这样写的.

There are a lot of explanations out there for what lambda functions are, but I can't find a thorough explanation of the syntax, and I am finding it very difficult to learn to replicate the syntax correctly because I don't understand why they're written as they are.

这是我遇到的一个常见案例,由 NetBeans 提供:

Here's a common case that I run into, courtesy NetBeans:

public static void main(String[] args) {
    SwingUtilities.invokeLater(() -> {
        new MainAppJFrame();
    });
}

不知何故,以下 lambda 表达式解析为匿名 Runnable 对象的 run() 方法:

So somehow, the following lambda expression is resolving into an anonymous Runnable object's run() method:

() -> {
    // do stuff
}

-> 是正确的 lambda 语法,对吗?大括号只是包含匿名方法代码.括号是否为空参数,因为在这种情况下我们正在创建一个 Runnable.run() 方法?

The -> is the lambda syntax proper, right? And the curly braces are simply containing the anonymous method code. Are the parentheses an empty argument, because in this case we're creating a Runnable.run() method?

这对我来说都相当不清楚.我假设编译器知道根据 SwingUtilities.invokeLater(Runnable) 方法预期的类型实例化一个匿名 Runnable?如果有两个 SwingUtilities.invokeLater 方法只是参数列表不同,会发生什么?显然在这种特定情况下没有,但在其他地方是可能的:

This is all rather unclear to me. I assume the compiler knows to instantiate an anonymous Runnable based on the type expected by the SwingUtilities.invokeLater(Runnable) method? What would happen if there were two SwingUtilities.invokeLater methods which differ only in parameter list? Obviously there aren't in this specific case, but it's possible elsewhere:

interface ExampleLambdaConsumer {
    public void doSomething(Runnable r);
    public void doSomething(java.lang.reflect.Method m);
}

class C implements ExampleLambdaConsumer {
    // implementations for doSomething methods here

    public static void main(String[] args) {
        doSomething(() -> {
            // lambda method body here
        }
    }
}

推荐答案

语法是:

arguments -> body

其中 arguments 可以是其中之一

where arguments can be either

  • ()

一个变量,如果可以从上下文推断出该变量的类型

a single variable if the type of that variable can be inferred from the context

括号中的变量序列,带或不带类型(或自 Java 11 起,带 var).
示例:(x)(x, y)(int x, int y)(var x, var y) (Java 11+).
以下无效:(int x, y), (x, var y), (var x, int y)

a sequence of variables, with or without types (or since Java 11, with var), in parentheses.
Examples: (x), (x, y), (int x, int y), (var x, var y) (Java 11+).
The following are invalid: (int x, y), (x, var y), (var x, int y)

body 可以是表达式或带有语句的 {...} 块.表达式(除了方法或构造函数调用)被简单地返回,即 () ->2 等价于 () ->{return 2;}

and body can be either an expression or a {...} block with statements. The expression (other than a method or constructor call) is simply returned, i.e. () -> 2 is equivalent to () -> {return 2;}

对于像 () 这样的 lambda 表达式 ->f()(主体是方法或构造函数调用表达式):

In case of lambda expressions like () -> f() (the body is a method or constructor call expression):

  • 如果f()返回void,它们等价于() ->{ F();}

否则,它们等同于 () ->{ F();}() ->{ 返回 f();}).编译器从调用上下文推断它,但通常它更喜欢后者.

otherwise, they are equivalent to either () -> { f(); } or () -> { return f(); }). The compiler infers it from the calling context, but usually it will prefer the latter.

因此,如果您有两个方法:void handle(Supplier)void handle(Runnable),则:

Therefore, if you have two methods: void handle(Supplier<T>) and void handle(Runnable), then:

  • handle(() -> { return f(); })handle(() -> x) 将调用第一个,

  • handle(() -> { return f(); }) and handle(() -> x) will call the first one,

handle(() -> { f(); } 将调用第二个,并且

handle(() -> { f(); } will call the second one, and

handle(() -> f()):

  • 如果 f() 返回 void 或不能转换为 T 的类型,那么它会调用第二个

  • if f() returns void or a type that is not convertible to T, then it will call the second one

如果f()返回一个可以转换为T的类型,那么它会调用第一个

if f() returns a type that is convertible to T, then it will call the first one

编译器尝试将 lambda 的类型与上下文匹配.我不知道确切的规则,但答案是:

The compiler tries to match the type of the lambda to the context. I don't know the exact rules, but the answer to:

如果有两个仅参数列表不同的 SwingUtilities.invokeLater 方法会发生什么?

What would happen if there were two SwingUtilities.invokeLater methods which differ only in parameter list?

是:这取决于这些参数列表是什么.如果另一个 invokeLater 也恰好有一个参数,并且该参数的类型也是具有 void*() 类型的一种方法的接口,那么它会抱怨它无法弄清楚您指的是哪种方法.

is: it depends on what would be those parameter lists. If the other invokeLater had also exactly one parameter and that parameter would be of type that is also an interface with one method of type void*(), well, then it would complain that it cannot figure out which method you mean.

为什么要写成这样?嗯,我认为这是因为 C# 和 Scala 中的语法几乎相同(它们使用 => 而不是 ->).

Why are they written as they are? Well, I think it's because syntax in C# and Scala is almost the same (they use => rather than ->).

这篇关于Java 的 lambda 语法的细分是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆