wake-up-neo.com

Warum brauche ich eine funktionale Schnittstelle, um mit Lambdas zu arbeiten?

Ich denke, diese Frage ist schon irgendwo da draußen, aber ich konnte sie nicht finden.

Ich verstehe nicht, warum es notwendig ist, eine funktionale Schnittstelle zu haben, um mit Lambdas zu arbeiten. Betrachten Sie das folgende Beispiel:

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

Dies funktioniert ohne Probleme, aber wenn Sie die kommentierten Zeilen auskommentieren, ist dies nicht der Fall. Warum? Nach meinem Verständnis sollte der Compiler in der Lage sein, die beiden Methoden zu unterscheiden, da sie unterschiedliche Eingabeparameter haben. Warum brauche ich eine funktionale Schnittstelle und blase meinen Code auf?

BEARBEITEN: Die verknüpften Duplikate haben meine Frage nicht beantwortet, da ich nach verschiedenen Methodenparametern frage. Ich habe hier wirklich nützliche Antworten erhalten, danke an alle, die geholfen haben! :)

EDIT2: Entschuldigung, ich bin offensichtlich kein Muttersprachler, aber um mich selbst zu präzisieren:

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

Ich frage nur nach den Argumenten. Der Methodenname spielt keine Rolle, aber für jede Methode gibt es eine eindeutige Reihenfolge unterschiedlicher Argumente. Aus diesem Grund könnte Oracle diese Funktion implementiert haben, anstatt nur eine einzige Methode pro "Lambda-Interface" zu ermöglichen.

29
codepleb

Wenn du schreibst:

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

Sie geben der void hans()-Methode der TestInterface eine Implementierung.

Wenn Sie einem Interface mit mehr als einer abstrakten Methode (d. H. Einer nicht funktionalen Schnittstelle) einen Lambda-Ausdruck zuweisen könnten, könnte der Lambda-Ausdruck nur eine der Methoden implementieren, wodurch die anderen Methoden nicht implementiert werden.

Sie können es nicht lösen, indem Sie der gleichen Variablen zwei Lambda-Ausdrücke mit unterschiedlichen Signaturen zuweisen (so wie Sie einer einzigen Variablen keine Referenzen von zwei Objekten zuweisen können und erwarten können, dass diese Variable gleichzeitig auf beide Objekte verweist).

28
Eran

Der wichtigste Grund, warum sie nur eine Methode enthalten müssen, ist, dass sonst leicht Verwirrung möglich ist. Wenn mehrere Methoden in der Schnittstelle zulässig sind, welche Methode sollte ein Lambda auswählen, wenn die Argumentlisten gleich sind?

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";
}
17
blagae

Sie scheinen nach anonymen Klassen zu suchen. Der folgende Code funktioniert:

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-Ausdrücke sind (meistens) eine kürzere Möglichkeit, anonyme Klassen mit nur einer Methode zu schreiben. (Ebenso sind anonyme Klassen eine Abkürzung für innere Klassen, die Sie nur an einer Stelle verwenden.)

5
immibis

Sie müssen keine funktionale Schnittstelle erstellen, um eine Lambda-Funktion zu erstellen. Über die Schnittstelle können Sie Instanzen für zukünftige Funktionsaufrufe erstellen.

In Ihrem Fall könnten Sie bereits vorhandene Schnittstelle Runable verwenden

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

und dann anrufen

r.run();

Sie können sich Lambda -> Als eine kurze Hand für Folgendes vorstellen:

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

Bei Lambda benötigen Sie nicht die anonyme Klasse, die im obigen Beispiel unter der Haube erstellt wird.

Dies hat jedoch einige Einschränkungen, um herauszufinden, welche Methode als Schnittstelle mit Lambdas bezeichnet werden soll, muss SAM (Single Abstract Method) sein. Dann haben wir nur eine Methode.

Für eine genauere Erklärung lesen Sie bitte:

Einführung in funktionale Schnittstellen - Ein in Java 8 neu erstelltes Konzept

Die funktionale Schnittstelle kann nur eine abstrakte Methode gemäß Java-Spezifikationen enthalten. 

Sicherlich kann Lambda-Ausdruck einmalig verwendet werden wie Ihr kommentierter Code, aber wenn es darum geht, Lambda-Ausdrücke als Parameter an den mimischen Funktionsrückruf zu übergeben, ist die funktionale Schnittstelle ein Muss, da in diesem Fall der variable Datentyp die funktionale Schnittstelle ist. 

Beispielsweise ist Runnable eine integrierte Funktionsschnittstelle:

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

Die Verwendung kann wie folgt demonstriert werden:

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

und das Ergebnis ist:

one-time lambda
one-time lambda
one-time lambda
lambda as variable
lambda as variable
lambda as variable
0
mzoz