Java 为什么我需要一个功能接口来使用lambdas?

Java 为什么我需要一个功能接口来使用lambdas?,java,lambda,java-8,functional-interface,Java,Lambda,Java 8,Functional Interface,我想这个问题已经在某处了,但我没能找到它 我不明白,为什么必须有一个功能接口来使用lambdas。考虑下面的例子: public class Test { public static void main(String...args) { TestInterface i = () -> System.out.println("Hans"); // i = (String a) -> System.out.println(a); i.

我想这个问题已经在某处了,但我没能找到它

我不明白,为什么必须有一个功能接口来使用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);
}
这样做没有问题,但是如果取消注释注释行,则不会出现问题。为什么?在我的理解中,编译器应该能够区分这两种方法,因为它们具有不同的输入参数。为什么我需要一个功能接口并放大我的代码

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

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. :)
    }
}
公共接口测试界面{
public void hans();//没有输入参数
public void hans(字符串a);//有1个输入参数,类型为String
public void hans(String a,int b);//有2个输入参数,1.type=String,2.type=int
public void hans(int a,int b);//也有2个输入参数,但与'hans(String a,int a);'不同,顺序也不同,因此您可以区分这两个参数 } 公开课考试{ 公共静态void main(字符串…参数){ TestInterface i=()->System.out.println(“Hans”); i=(字符串a)->System.out.println(a); i=(字符串a,int b)->System.out.println(a+b); i=(inta,intb)->System.out.println(a); i、 hans(2,3);//将调用哪个方法?当然是将接受2个整数参数的方法。:) } }

我问的是关于争论的问题。方法名称无关紧要,但每个方法都有不同参数的唯一顺序,因此,Oracle本可以实现此功能,而不是让每个“Lambda接口”都有一个方法。创建Lambda函数不必创建函数接口。该接口允许您为将来的函数调用创建实例

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

Runnable r=()->System.out.println(“Hans”)

然后打电话

r.run()

您可以将lambda
->
视为以下内容的唯一缩写:

Runnable r = new Runnable() {
     void run() {
          System.out.println("Hans");`
     }
}
对于lambda,您不需要匿名类,在上面的示例中,匿名类是在后台创建的

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

有关更详细的解释,请阅读:

当你写作时:

TestInterface i = () -> System.out.println("Hans");
您给出了
TestInterface
void hans()
方法的实现

如果可以将lambda表达式分配给具有多个抽象方法(即非函数接口)的接口,则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表达式(大部分)是只使用一个方法编写匿名类的较短方法。(同样,匿名类是仅在一个位置使用的内部类的简写)

函数接口只能包含一个抽象方法

当然,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);
    }
}

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

  • 在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只适用于具有一个方法或函数接口的接口。

@TrudleR,那么java将是一种函数语言。如果您对JVM上的这种实现感兴趣。你可以试试Scala语言。@TrudleR:“如果你可以调用你实现了一个实体的方法”-当你有一个任意接口实现的实例时,你怎么知道实现了哪些方法呢?TrudleR,你让我想到了:)但是我想,如果他们允许的话,他们怎么会打开潘多拉盒子呢“只需调用实现主体的方法即可“..:lambda定义了1个方法,而您的接口是2的契约;违背这项合同会使你的物品接收混乱。。另外,如果您的接口有多个带有字符串参数的方法,编译器将不知道哪个方法与lambda表达式匹配。如果你想激进,你可以考虑NoDE.JS,它根本不需要合同。
  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);
  }