java - lambda 调用如何与接口(interface)交互?

标签 java lambda java-8 interface

下面显示的代码片段有效。但是,我不确定它为什么有效。我不太明白 lambda 函数如何将信息传递到接口(interface)的逻辑。

控制权被传递到哪里?编译器如何理解循环中的每个n以及创建的每个消息

此代码编译并给出预期结果。我只是不确定如何。

import java.util.ArrayList;
import java.util.List;

public class TesterClass {

    public static void main(String[] args) {

        List<String> names = new ArrayList<>();

        names.add("Akira");
        names.add("Jacky");
        names.add("Sarah");
        names.add("Wolf");

        names.forEach((n) -> {
            SayHello hello = (message) -> System.out.println("Hello " + message);
            hello.speak(n);
        });
    }

    interface SayHello {
        void speak(String message);
    }
}

最佳答案

SayHello 是一个单一抽象方法接口(interface),它有一个接受字符串并返回 void 的方法。这类似于消费者。您只是以使用者的形式提供该方法的实现,这类似于以下匿名内部类实现。

SayHello sh = new SayHello() {
    @Override
    public void speak(String message) {
        System.out.println("Hello " + message);
    }
};

names.forEach(n -> sh.speak(n));

幸运的是,您的接口(interface)有一个方法,以便类型系统(更正式地说,类型解析算法)可以将其类型推断为 SayHello。但如果它有 2 个或更多方法,这是不可能的。

但是,更好的方法是在 for 循环之前声明使用者并使用它,如下所示。声明每次迭代的实现都会创建不必要的对象,这对我来说似乎违反直觉。这是使用方法引用而不是 lambda 的增强版本。这里使用的有界方法引用调用上面声明的 hello 实例上的相关方法。

SayHello hello = message -> System.out.println("Hello " + message);
names.forEach(hello::speak);

更新

鉴于无状态 lambda 表达式仅在创建实例时才从其词法作用域中捕获任何内容,因此这两种方法都仅创建 SayHello 的一个实例,并且不会有任何 yield 建议的方法。然而,这似乎是一个实现细节,直到现在我才知道。因此,更好的方法是将消费者传递给您的 forEach,如下面评论中所建议的。另请注意,所有这些方法都仅创建 SayHello 接口(interface)的一个实例,而最后一个更为简洁。它看起来是这样的。

names.forEach(message -> System.out.println("Hello " + message));

这个answer会让您对此有更多的了解。以下是 JLS §15.27.4 的相关部分: Lambda 表达式的运行时评估

These rules are meant to offer flexibility to implementations of the Java programming language, in that:

  • A new object need not be allocated on every evaluation.

事实上,我最初认为每次评估都会创建一个新实例,这是错误的。 @Holger 感谢您指出这一点,很好。

关于java - lambda 调用如何与接口(interface)交互?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58676928/

相关文章:

java - 尝试使用多个资源会导致 Sonar qube 问题

java - 使用自己创建的jar文件时出现ClassNotFoundException

java - 改变牙套的样式

java - 为什么java类的构造函数不被继承呢?

python - 在 Python optimize.root 中将参数传递给目标函数

java - 将 Future 与 ExecutorService 结合使用

java - Oracle 中的 XMLGregorianCalendar 至今

python - 修改python中的函数而不调用它

c# - Lambda 表达式 Compile() 方法有什么作用?

java - Java如何知道使用lambda表达式时应该重写哪个方法