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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/33010594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 14:09:27  来源:igfitidea点击:

Why do I need a functional Interface to work with lambdas?

javalambdajava-8functional-interface

提问by codepleb

I think this question is already somewhere out there, but I wasn't able to find it.

我认为这个问题已经在某个地方了,但我找不到它。

I don't understand, why it's necessary to have a functional interface to work with lambdas. Consider the following example:

我不明白,为什么需要一个函数式接口来处理 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);
}

This works without problems, but if you uncomment the commented lines, it doesn't. Why? In my understanding, the compiler should be able to distinguish the two methods, since they have different input-parameters. Why do I need a functional interface and blow up my code?

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

EDIT: The linked duplicates didn't answer my question because I'm asking about different method-parameters. But I got some really useful answers here, thanks to everyone who helped! :)

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

EDIT2: Sorry, I'm obviously not a native speaker, but to precise myself:

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. :)
    }
}

All I'm asking is about the arguments. The method name doesn't matter, but each method takes an unique order of different arguments and because of that, Oracle could have implemented this feature instead just making a single method possible per "Lambda-Interface".

我要问的只是关于论点。方法名称无关紧要,但每个方法都采用不同参数的唯一顺序,因此,Oracle 可以实现此功能,而不是只为每个“Lambda 接口”创建一个方法。

采纳答案by Eran

When you write :

当你写:

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

You give an implementation to the void hans()method of the TestInterface.

你给一个实现void hans()的方法TestInterface

If you could assign a lambda expression to an interface having more than one abstract method (i.e. a non functional interface), the lambda expression could only implement one of the methods, leaving the other methods unimplemented.

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

You can't solve it by assigning two lambda expressions having different signatures to the same variable (Just like you can't assign references of two objects to a single variable and expect that variable to refer to both objects at once).

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

回答by Damian Leszczyński - Vash

You do not have to create a functional interface in order to create lambda function. The interface allow you to create instance for future function invocation.

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

In your case you could use already existing interface Runable

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

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

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

and then call

然后打电话

r.run();

r.run();

You can think of lambda ->as only short hand for:

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

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

With lambda you do not need the anonymous class, that is created under the hood in above example.

使用 lambda 你不需要匿名类,它是在上面的例子中创建的。

But this has some limitation, in order to figure out what method should be called interface used with lambdas must be SAM (Single Abstract Method). Then we have only one method.

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

For more detailed explanation read:

更详细的解释请阅读:

Introduction to Functional Interfaces – A Concept Recreated in Java 8

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

回答by blagae

The most important reason why they must contain only one method, is that confusion is easily possible otherwise. If multiple methods were allowed in the interface, which method should a lambda pick if the argument lists are the same ?

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

回答by user253751

You seem to be looking for anonymous classes. The following code works:

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

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 expressions are (mostly) a shorter way to write anonymous classes with only one method. (Likewise, anonymous classes are shorthand for inner classes that you only use in one place)

Lambda 表达式(主要是)是一种仅用一种方法编写匿名类的较短方法。(同样,匿名类是仅在一处使用的内部类的简写)

回答by mzoz

Functional interface can only contain exactly one abstract method according to java specs.

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

Surely lambda expression can be one-time used as your commented code does, but when it comes to passing lambda expression as parameter to mimic function callback, functional interface is a must because in that case the variable data type is the functional interface.

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

For example, Runnableis a built-in functional interface:

例如,Runnable是一个内置的函数式接口:

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

The usage can be demonstrated as below:

用法可以如下所示:

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

and the result is:

结果是:

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

回答by kumarras

A lambda expression is nothing but a shortcut to defining an implementation of a functional interface. It is equivalent to an instance of a functional interface implementation.

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