为什么我需要一个function界面来处理lambdas?

我认为这个问题已经存在,但我无法找到它。

我不明白,为什么有必要使用function界面来处理lambdas。 请考虑以下示例:

public class Test { public static void main(String...args) { TestInterface i = () -> System.out.println("Hans"); // i = (String a) -> System.out.println(a); i.hans(); // i.hans("Hello"); } } public interface TestInterface { public void hans(); // public void hans(String a); } 

这没有问题,但如果您取消注释注释行,它不会。 为什么? 根据我的理解,编译器应该能够区分这两种方法,因为它们具有不同的输入参数。 为什么我需要一个function界面并炸毁我的代码?

编辑:链接副本没有回答我的问题,因为我问的是不同的方法参数。 但是我在这里得到了一些非常有用的答案,感谢所有帮助过的人! 🙂

编辑2:对不起,我显然不是母语人士,但为了准确自己:

 public interface TestInterface { public void hans(); //has no input parameters
public void hans(String a); //has 1 input parameter, type String
public void hans(String a, int b); //has 2 input parameters, 1. type = String, 2. type = int
public void hans(int a, int b); //has also 2 input parameters, but not the same and a different order than `hans(String a, int a);`, so you could distinguish both } public class Test { public static void main(String...args) { TestInterface i = () -> System.out.println("Hans"); i = (String a) -> System.out.println(a); i = (String a, int b) -> System.out.println(a + b); i = (int a, int b) -> System.out.println(a); i.hans(2, 3); //Which method would be called? Of course the one that would take 2 integer arguments. :) } }

我所要问的只是争论。 方法名称无关紧要,但每个方法都采用不同参数的唯一顺序,因此,Oracle可以实现此function,而只是根据“Lambda-Interface”使单个方法成为可能。

当你写:

 TestInterface i = () -> System.out.println("Hans"); 

您为TestInterfacevoid hans()方法提供了一个实现。

如果可以将lambda表达式分配给具有多个抽象方法的接口(即非function接口),则lambda表达式只能实现其中一个方法,而其他方法则不实现。

您无法通过将两个具有不同签名的lambda表达式分配给同一个变量来解决它(就像您不能将两个对象的引用分配给单个变量并期望该变量一次引用这两个对象一样)。

他们必须只包含一种方法的最重要原因是,否则很容易产生混淆。 如果接口中允许多个方法,如果参数列表相同,那么lambda选择哪个方法?

 interface TestInterface { void first(); void second(); // this is only distinguished from first() by method name String third(); // maybe you could say in this instance "well the return type is different" Object fourth(); // but a String is an Object, too ! } void test() { // which method are you implementing, first or second ? TestInterface a = () -> System.out.println("Ido mein ado mein"); // which method are you implementing, third or fourth ? TestInterface b = () -> "Ido mein ado mein"; } 

你似乎在寻找匿名课程 。 以下代码有效:

 public class Test { public static void main(String...args) { TestInterface i = new TestInterface() { public void hans() { System.out.println("Hans"); } public void hans(String a) { System.out.println(a); } }; i.hans(); i.hans("Hello"); } } public interface TestInterface { public void hans(); public void hans(String a); } 

Lambda表达式(大多数)是仅使用一种方法编写匿名类的较短方式。 (同样,匿名类是您只在一个地方使用的内部类的简写)

您不必创建function接口即可创建lambda函数。 该接口允许您为将来的函数调用创建实例。

在您的情况下,您可以使用现有的Runable接口

Runnable r = () -> System.out.println("Hans");

然后打电话

r.run();

您可以将lambda ->视为以下的简写:

 Runnable r = new Runnable() { void run() { System.out.println("Hans");` } } 

使用lambda,您不需要匿名类,这是在上面的示例中创建的。

但是这有一些限制,为了弄清楚应该用什么方法调用lambdas使用的接口必须是SAM(单一抽象方法)。 然后我们只有一种方法。

有关详细说明,请阅读:

function接口简介 – 用Java 8重新创建的概念

根据java规范,function接口只能包含一个抽象方法。

当然,lambda表达式可以像注释代码那样一次性使用,但是当将lambda表达式作为参数传递给模拟函数回调时,function接口是必须的,因为在这种情况下,变量数据类型是function接口。

例如, Runnable是一个内置的function接口:

 public interface Runnable() { public void run(); } 

用法可以如下所示:

 public class LambdaTest { // data type of parameter 'task' is functional interface 'Runnable' static void doSeveralTimes(Runnable task, int repeat) { for (int i = 0; i < repeat; i++) { task.run(); } } public static void main(String[] args) { // one-time lambda doSeveralTimes(() -> { System.out.println("one-time lambda"); }, 3); // lambda as variable Runnable test; test = () -> { System.out.println("lambda as variable"); }; doSeveralTimes(test, 3); } } 

结果是:

 one-time lambda one-time lambda one-time lambda lambda as variable lambda as variable lambda as variable