2013-07-28 10 views
72

Lesen auf der Java-8-Spezifikation, ich sehe immer wieder Referenzen auf "SAM-Typen". Ich konnte keine klare Erklärung dafür finden, was das ist.Was ist ein 'SAM-Typ' in Java?

Was ist ein SAM-Typ und was ist ein Beispielszenario für die Verwendung?

+4

Siehe http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html (was ich nach einer einzigen Suche gefunden habe, die mich zu einer anderen SO-Frage geführt hat). –

+0

Das ist genau das, was ich brauchte. Vielen Dank! Nur aus Neugier, welches Keyword haben Sie bei Ihrer Suche verwendet? – Cody

+2

Bitte weisen Sie Personen nicht auf veraltete Informationen hin. Eine etwas längere Suche hätte Sie zur aktuelleren Version geführt: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html, die selbst 18 Monate alt ist und jetzt an vielen Orten veraltet.Die Frage des OP wird unter http://www.lambdafaq.org/what-is-a-functional-interface/ beantwortet, eine Seite in einer FAQ, die ich versuche, mich auf dem Laufenden zu halten, was sich bis vor kurzem in einem rasanten Wandel befand Sprach- und API-Entwicklung. –

Antwort

79

the link Jon posted bei Zusammenfassend immer es geht nach unten, "SAM" steht für "Single abstrakte Methode" und "SAM-Typ" bezieht sich auf Schnittstellen wie Runnable, Callable usw. Lambda-Ausdrücke, ein neues Feature in Java 8 , werden als SAM-Typ betrachtet und können frei zu ihnen konvertiert werden.

Zum Beispiel mit einer Schnittstelle wie folgt aus:

public interface Callable<T> { 
    public T call(); 
} 

Sie können ein Callable mit Lambda-Ausdrücke wie folgt erklären:

Callable<String> strCallable =() -> "Hello world!"; 
System.out.println(strCallable.call()); // prints "Hello world!" 

Lambda-Ausdrücke sind in diesem Zusammenhang meist nur syntaktischer Zucker. Sie sehen im Code besser aus als anonyme Klassen und sind weniger restriktiv bei der Methodenbenennung. Nehmen Sie dieses Beispiel aus dem Link:

class Person { 
    private final String name; 
    private final int age; 

    public static int compareByAge(Person a, Person b) { ... } 

    public static int compareByName(Person a, Person b) { ... } 
} 

Person[] people = ... 
Arrays.sort(people, Person::compareByAge); 

Dies schafft eine Comparator eine bestimmte Methode verwenden, die nicht den gleichen Namen wie Comparator.compare nicht teilt, auf diese Weise müssen Sie nicht die Schnittstelle Benennung von Methoden folgen und Sie können Haben mehrere Vergleichsüberschreibungen in einer Klasse, dann erstellen Sie die Vergleicher im laufenden Betrieb über die Lambda-Ausdrücke.

Tiefer gehen ...

Auf einer tieferen Ebene, Java implementiert diese mit der invokedynamic Anweisung Bytecode hinzugefügt in Java 7. Ich sagte vorhin, dass ein Lambda erklärt zu einer Instanz von Callable oder Comparable ähnlich schafft anonyme Klasse, aber das ist nicht streng wahr. Stattdessen wird beim ersten Aufruf des invokedynamic ein Lambda-Funktionshandler erstellt, der LambdaMetafactory.metafactory method verwendet, und verwendet dann diese zwischengespeicherte Instanz in zukünftigen Aufrufen des Lambda. Weitere Informationen finden Sie in this answer. Dieser Ansatz ist komplex und enthält sogar Code, der primitive Werte und Referenzen direkt aus dem Stapelspeicher lesen kann, um sie in Ihren Lambda-Code zu übertragen (zB um ein Object[] Array zuzuteilen, um Ihr Lambda aufzurufen), aber es erlaubt Zukunft Iterationen der Lambda-Implementierung, um alte Implementierungen zu ersetzen, ohne sich um die Bytecode-Kompatibilität kümmern zu müssen. Wenn die Entwickler von Oracle die zugrunde liegende Lambda-Implementierung in einer neueren Version der JVM ändern, verwendet Lambdas, das auf einer älteren JVM kompiliert wurde, die neuere Implementierung.


Als eine Nebenbemerkung ist die Syntax auf der Verknüpfung veraltet. Werfen Sie einen Blick auf die Lambda Expressions Java Trail, um die aktuelle Syntax zu sehen.

+0

bist du sicher '# {" Hallo Welt! " }; 'ist die richtige Syntax? Ich dachte, ich würde es in einem Lambda-Ausdruck ausdrücken wie '() ->" Hallo Welt! ". – asgs

+0

Ah, ja. Ich habe gerade @ Maurices Kommentare gelesen. Sie sollten diesen Beitrag bearbeiten, um die neuesten Informationen zu berücksichtigen. Gut zu wissen, dass '# {}' wie Lambdas zuvor dargestellt wurden. – asgs

+1

@asgs Ich hatte unten einen kleinen Klappentext, der auf den Java-Pfad zeigte, aber ich ging weiter und aktualisierte die Antwort trotzdem, um die aktuelle Syntax zu verwenden. – Brian