Java的lambda语法有什么细分?

muf*_*fin 35 java syntax lambda java-8

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

有很多解释了那里什么拉姆达功能,但我找不到语法的详尽的解释,而我发现很难学会正确复制的语法,因为我不明白为什么他们"按原样重写.

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

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

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

() -> {
    // do stuff
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Kar*_*l S 43

语法是:

arguments -> body
Run Code Online (Sandbox Code Playgroud)

哪里arguments都可以

  • ()

  • 如果可以从上下文中推断出该变量的类型,则为单个变量

  • 括号中包含或不包含类型的变量序列

和body可以是表达式,也可以是var带语句的块.简单地返回表达式,即(x)等同于(x, y)


编辑:如果lambda表达式如下(int x, int y):

  • 如果(var x, var y)返回(int x, y),它们相当于(x, var y)

  • 否则,它们相当于(var x, int y)body.编译器从调用上下文推断出它,但通常它会更喜欢后者.

因此,如果您有两种方法:{...}() -> 2,那么:

  • () -> {return 2;}() -> f()打电话给第一个,

  • f() 将拨打第二个,并且

  • void:

    • 如果() -> { f(); }返回() -> { f(); }或者不可转换的类型() -> { return f(); }),那么它将调用第二个

    • 如果void handle(Supplier<T>)返回一个可转换为的类型void handle(Runnable),那么它将调用第一个类型


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

如果有两个SwingUtilities.invokeLater方法只在参数列表中有所不同,会发生什么?

是:它取决于那些参数列表.如果handle(() -> { return f(); })另一个参数只有一个参数,并且该参数的类型也是一个类型的方法的接口handle(() -> x),那么它会抱怨它无法找出你的意思.

他们为什么这样写?好吧,我认为这是因为C#和Scala中的语法几乎相同(他们使用handle(() -> { f(); }而不是handle(() -> f())).

  • 参数 -&gt; 正文 :-) 为什么 Oracle 教程没有这么简单? (3认同)

Xab*_*ter 10

语法是

(parameter_list_here) -> { stuff_to_do; }
Run Code Online (Sandbox Code Playgroud)

如果花括号是单个表达式,则可以省略花括号.如果参数列表是单个参数,则可以省略参数列表周围的常规括号.

该语法仅适用于所有功能接口.@FunctionalInterface注释告诉编译器您打算编写这样的接口,并在不满足要求时给出编译错误 - 例如,它必须只有1个可重写的方法.

@FunctionalInterface
interface TestInterface {
    void dostuff();
}
Run Code Online (Sandbox Code Playgroud)

Runnable也是这样宣布的.其他接口不是,它们不能与lambda函数一起使用.

现在我们已经使用不带参数的方法创建了一个新的功能接口,我们如何测试签名中有关"碰撞"的问题?

public class Main {
    private void test(Runnable r) {

    }
    private void test(TestInterface ti) {

    }
    public static void main(String[] args) { 
        test(() -> { System.out.println("test");})
    }

    @FunctionalInterface
    interface TestInterface {
        void dostuff();
    }
}
Run Code Online (Sandbox Code Playgroud)

结果:编译错误:对方法测试进行严格调用.

您看,编译器/ VM(如果完成运行时)找到适当的方法及其参数列表,并查看参数是否是功能接口,如果是,则创建该接口的匿名实现.从技术上讲(在字节代码中)它与匿名类不同,但在其他方面相同(您将看不到Main $ 1.class文件).

您的示例代码(由Netbeans提供)也可以替换为

SwingUtilities.invokeLater(MainAppJFrame::new);
Run Code Online (Sandbox Code Playgroud)

顺便说一句.:)

  • 可以使用lambda,其中需要使用单个抽象方法引用任何接口.该接口不需要具有`@ FunctionalInterface`注释.该注释是*intent*与lambda一起使用的信号,它改变了javadoc,但它不是必需的. (4认同)

Pra*_*kam 8

Lambda表达式基本上在Java 8中采用,以简化作为匿名函数覆盖进程函数.

它们只是覆盖旧java匿名函数的快捷方式.

请参考以下示例:

假设您有接口A,它只有一个声明如下的方法:

interface A{        
    void print();           
}
Run Code Online (Sandbox Code Playgroud)

现在使用旧的java风格,我们将以匿名的方式覆盖它,如下所示:

new A() {           
        @Override
        public void print() {
            System.out.println("in a print method");                
        }           
};
Run Code Online (Sandbox Code Playgroud)

另外现在使用java 8 lambda表达式,我们将使用它如下:

() -> System.out.println("in a print method");
Run Code Online (Sandbox Code Playgroud)

在这里我们可以在->操作符之前传递方法所需的参数,然后在操作符之后覆盖body ->.

我们需要实现的唯一设置是我们需要使用@FunctionalInterface声明接口, 如下所示:

 @FunctionalInterface
 interface A{        
    void print();           
 }
Run Code Online (Sandbox Code Playgroud)

注意: - lambda表达式只能用于只有一个非默认方法的"功能"接口.

  • 易于理解的解释 (2认同)