2016-07-12 3 views
1

Java 7funktioniert Lambda-Ausdruck an einer Schnittstelle?

List<Person> personList = Person.createShortList(); 

// Sort with Inner Class 
Collections.sort(personList, new Comparator<Person>() { 
    public int compare(Person p1, Person p2) { 
     return p1.getSurName().compareTo(p2.getSurName()); 
    } 
}); 

Java 8

Collections.sort(personList, (Person p1, Person p2) -> 
       p1.getSurName().compareTo(p2.getSurName())); 

for (Person p : personList) { 
    p.printName(); 
} 

Wenn die Schnittstelle Comparator 2 Methoden hat und nicht nur eine compare ist es möglich, Lambda zu benutzen?

zum Beispiel

public interface Comparator<T> { 
    int compare(T o1, T o2); 
    int compareTest(T o1, T o2); 
} 
+2

Ein Lambda muss eine Schnittstelle mit genau einer abstrakten Methode implementieren. Es kann eine beliebige Anzahl von Standardmethoden haben. –

+2

Übrigens können Sie 'Collections.sort (personList, Comparator.comparing (p-> p.getSurName()));' verwenden, um sich nicht zu wiederholen. Alternativ: 'Collections.sort (personList, Comparator.comparation (Person :: getSurName));' – Holger

Antwort

4

Lambdas verwendet werden können, wo Implementierungen von funktionalen Schnittstellen erwartet werden. Die Definition einer Funktionsschnittstelle ist in JLS§9.8:

A funktionale Schnittstelle ist eine Schnittstelle, die nur eine abstrakte Methode (abgesehen von den Methoden der Object), und stellt somit einen einzige Funktion Vertrag hat. Diese "single" -Methode kann die Form von mehreren abstrakten Methoden mit Override-äquivalenten Signaturen haben, die von Superschnittstellen geerbt werden; In diesem Fall repräsentieren die geerbten Methoden logisch eine einzige Methode.

So in Ihrem Beispiel nicht, wenn es auf Comparator (compare und compareTest) zwei abstrakte Methoden waren, können Sie es nicht implementieren eine Lambda verwenden.

Zum Beispiel funktioniert das:

@FunctionalInterface 
interface Foo { 
    void method1(int x); 
} 

public class Example { 
    public static final void main(String[] args) { 
     new Example().testFoo(x -> { 
      System.out.println(x); 
     }); 
    } 

    private void testFoo(Foo f) { 
     for (int x = 0; x < 5; ++x) { 
      f.method1(x); 
     } 
    } 
} 

... aber wenn wir in den Foo:

// WON'T COMPILE 
@FunctionalInterface 
interface Foo { 
    void method1(int x); 
    void method2(int x); 
} 

... es wird nicht mehr kompilieren, weil es nicht mehr ist eine funktionale Schnittstelle . (Wenn wir die Anmerkung entfernt, würde die Schnittstelle [natürlich] kompilieren, aber unser Gebrauch davon über eine Lambda würde nicht.)

Bitte beachte, dass wir eine Standard Methode Foo könnten hinzufügen:

@FunctionalInterface 
interface Foo { 
    void method1(int x); 
    default void method2(int x) { 
     // ... 
    } 
} 

Das ist in Ordnung, weil es nur eine abstrakte Methode auf der Schnittstelle gibt.

+1

Um genau zu sein, muss eine funktionale Schnittstelle genau eine 'abstrakte' Methode haben, die nicht mit einer in' java.lang deklarierten Methode übereinstimmt .Objekt'. Dies ist besonders wichtig, da die Schnittstelle der Frage [Comparator] (https://docs.oracle.com/javase/8/docs/api/?java/util/Comparator.html) zwei "abstract" hat Methoden, aber [einer von ihnen] (https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html # equals-java.lang.Object-) entspricht einer [Methode deklariert in 'Object'] (https://docs.oracle.com/javase/ 8/docs/api/java/lang/Objekt.html # gleich-java.lang.Objekt-). – Holger

+2

So 'Comparator' ist ein schönes Beispiel für eine funktionale Schnittstelle, die sie alle:' statische' Methoden, 'default' Methoden und eine zweite' abstrakte' Methode, die eine Methode in 'java.lang.Object' ... – Holger

5

Funktionale Schnittstellen benötigen genau eine abstrakte Methode, was für Ihre Schnittstelle nicht der Fall ist. Sie können jedoch eine Standardimplementierung für eine der Methoden bereitstellen. In diesem Fall würde es funktionieren:

@FunctionalInterface 
public interface Comparator<T> { 

    int compare(T o1, T o2); 

    default int reverseCompare(T o1, T o2) { 
     return compare(o2, o1); 
    } 
} 
+1

Heh, nur kam vom Testen der Standardmethoden zurück (ich war mir nicht sicher, ob sie funktionieren würden) und aktualisierte meine Antwort, und ich finde, dass du sie auch ausgerufen hast. :-) –

Verwandte Themen