44

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

我不明白,为什么必须有一个函数式接口才能使用 lambda。考虑以下示例:

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);
}

这可以正常工作,但是如果您取消注释注释行,则不会。为什么?据我了解,编译器应该能够区分这两种方法,因为它们具有不同的输入参数。为什么我需要一个功能接口并炸毁我的代码?

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

EDIT2:对不起,我显然不是母语人士,但要准确地说:

public interface TestInterface {
    public void hans();                 //has no input parameters</br>
    public void hans(String a);         //has 1 input parameter, type String</br>
    public void hans(String a, int b);  //has 2 input parameters, 1. type = String, 2. type = int</br>
    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 可以实现此功能,而不是只为每个“Lambda 接口”提供一个方法。

4

7 回答 7

41

当你写:

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

你给void hans().TestInterface

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

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

于 2015-10-08T08:40:07.970 回答
25

它们必须只包含一种方法的最重要原因是,否则很容易混淆。如果接口中允许使用多个方法,如果参数列表相同,则 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";
}
于 2015-10-08T08:51:36.337 回答
7

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

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 表达式(大多数情况下)是一种只用一种方法编写匿名类的更短的方法。(同样,匿名类是你只在一个地方使用的内部类的简写)

于 2015-10-09T11:20:24.470 回答
5

您不必为了创建 lambda 函数而创建函数式接口。该接口允许您为将来的函数调用创建实例。

在您的情况下,您可以使用已经存在的接口 Runable

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

然后打电话

r.run();

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

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

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

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

更详细的解释请阅读:

函数式接口简介——Java 8 中重新创建的概念

于 2015-10-08T08:37:01.990 回答
2
  • 在java中实现接口时,需要实现其所有抽象方法(否则实现类必须是接口)。

  • Java 编译器在内部扩展 lambda 表达式,其中包含带有方法的类定义,以及用于实例化此类的语句。目前,java 不支持/提供一种方法,让超过 1 个 lambda 与 1 个接口相关联。

      public class Test {
          public static void main(String...args) {
              TestInterface i = () -> System.out.println("Hans"); // this will not compile as the implementation for public void hans(String a); can not be provided/is not found
              //i = (String a) -> System.out.println(a); //this can not add an implementation for 2nd method to i after compilation of 1st lambda
           }
      }
      public interface TestInterface {
          public void hans();
          public void hans(String a);
      }
    

这就是 java 中的 lambda 仅适用于具有一种方法或功能接口的接口的原因。

于 2021-01-20T10:34:16.020 回答
0

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

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

比如Runnable是一个内置的功能接口:

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
于 2018-08-09T09:34:39.630 回答
0

lambda 表达式只不过是定义函数式接口实现的快捷方式。它相当于一个功能接口实现的实例。

于 2020-05-25T09:19:26.043 回答