java 为什么我需要一个函数接口来使用lambdas?

odopli94  于 2023-02-07  发布在  Java
关注(0)|答案(7)|浏览(140)

我想这个问题已经存在了,但我没能找到它。
我不明白,为什么要有一个函数接口来使用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);
}

这是没有问题的,但是如果你取消注解行的注解,它就没有问题了。为什么呢?在我的理解中,编译器应该能够区分这两个方法,因为它们有不同的输入参数。为什么我需要一个函数接口并放大我的代码呢?
编辑:链接的副本没有回答我的问题,因为我问的是不同的方法参数。但我在这里得到了一些非常有用的答案,感谢所有帮助我的人!:)
编辑2:对不起,我显然不是一个母语为英语的人,但准确地说:

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接口”都有一个方法。

3htmauhk

3htmauhk1#

当你写:

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

您给出了TestInterfacevoid hans()方法的实现。
如果你可以将一个lambda表达式赋给一个有多个抽象方法的接口(即一个非函数接口),那么这个lambda表达式只能实现其中一个方法,而其他的方法都不能实现。
不能通过将两个具有不同签名的lambda表达式赋给同一个变量来解决这个问题(就像不能将两个对象的引用赋给一个变量并期望该变量同时引用这两个对象一样)。

nnsrf1az

nnsrf1az2#

它们必须只包含一个方法的最重要的原因是,否则很容易混淆。如果接口中允许多个方法,那么当参数列表相同时,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";
}
rm5edbpk

rm5edbpk3#

您似乎在寻找匿名类。下面的代码可以正常工作:

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

rsl1atfo

rsl1atfo4#

你不需要为了创建lambda函数而创建函数接口。接口允许你为将来的函数调用创建示例。
在您的情况下,您可以使用已经存在的接口Runable
Runnable r = () -> System.out.println("Hans");
然后呼叫
r.run();
你可以把lambda ->看作是以下表达式的简写:

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

有了lambda,你就不需要匿名类了,在上面的例子中,匿名类是在幕后创建的。
但是这有一些局限性,为了弄清楚什么方法应该被调用,与lambda一起使用的接口必须是SAM(单一抽象方法),这样我们就只有一个方法。
更详细的解释如下:
Introduction to Functional Interfaces – A Concept Recreated in Java 8

f0brbegy

f0brbegy5#

  • 在java中,当一个接口被实现时,它的所有抽象方法都需要被实现(否则实现类将不得不是一个接口)。
  • Java编译器使用类定义和方法在内部扩展lambda表达式,以及示例化该类的语句。目前Java不支持/不提供将多个lambda与一个接口关联的方法。
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只能处理一个只有一个方法或函数接口的接口。

k4emjkb1

k4emjkb16#

根据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
au9on6nz

au9on6nz7#

lambda表达式只是定义函数接口实现的捷径,它等价于函数接口实现的示例。

相关问题