2013-07-28 17 views
72

Czytając specyfikację Java-8, widzę odniesienia do "typów SAM". Nie byłem w stanie znaleźć jasnego wyjaśnienia tego, co to jest.Co to jest "typ SAM" w Javie?

Co to jest typ SAM i jaki jest przykład scenariusza, w którym można go użyć?

+4

Zobacz http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html (które znalazłem po jednym wyszukiwaniu, który zabrał mnie do innego pytania SO). –

+0

To dokładnie to, czego potrzebowałem. Dzięki! Z czystej ciekawości, jakiego słowa kluczowego użyłeś w wyszukiwaniu? – Cody

+2

Nie kieruj ludzi do nieaktualnych informacji. Nieco dłuższe wyszukiwanie spowodowałoby przejście do bardziej aktualnej wersji: http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html, która sama ma 18 miesięcy i teraz przestarzałe w wielu miejscach.Odpowiedzi na pytanie PO można znaleźć na stronie http://www.lambdafaq.org/what-is-a-functional-interface/, na jednej stronie w FAQ, na której staram się być na bieżąco, co do niedawna szybko się zmieniało rozwój języka i API. –

Odpowiedz

79

Podsumowując the link Jon posted w przypadku kiedykolwiek idzie w dół, „SAM” jest skrótem od „jednej metody abstrakcyjnej” i „SAM-type” odnosi się do interfejsów jak Runnable, Callable itp lambda wyrażeń, nową funkcję w Java 8 , są uznawane za typ SAM i można je dowolnie konwertować.

Na przykład, z interfejsem takich jak to:

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

Można zadeklarować Callable przy użyciu wyrażeń lambda tak:

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

lambda wyrażenia w tym kontekście są przeważnie tylko cukier syntaktyczny. Wyglądają lepiej w kodzie niż w klasach anonimowych i są mniej restrykcyjne w zakresie nazewnictwa metod. Weźmy ten przykład z linku:

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

Stwarza to Comparator za pomocą określonej metody, które nie mają takie same nazwy jak Comparator.compare, w ten sposób nie trzeba śledzić nazewnictwo interfejsu metod i można mają wiele nadpisań porównawczych w klasie, a następnie tworzą komparatory w locie za pomocą wyrażeń lambda.

zagłębiając ...

Na głębszym poziomie, Java implementuje je za pomocą instrukcji kodu bajtowego invokedynamic dodanej w Javie 7. powiedziałem wcześniej, że deklarując lambda tworzy instancję Callable lub Comparable podobny do anonimowa klasa, ale to nie jest prawda. Zamiast tego, po raz pierwszy wywoływana jest nazwa invokedynamic, tworzy ona procedurę obsługi funkcji Lambda przy użyciu LambdaMetafactory.metafactory method, a następnie używa tej pamięci podręcznej w przyszłych wywołaniach Lambda. Więcej informacji można znaleźć w this answer.

To podejście jest złożone, a nawet zawiera kod, który odczytuje prymitywne wartości i odniesienia bezpośrednio z pamięci stosu, aby przekazać kod Lambda (np. Aby ominąć konieczność przydzielenia tablicy Object[] w celu wywołania Lambda), ale pozwala na przyszłość iteracje implementacji Lambda w celu zastąpienia starych implementacji bez martwienia się o zgodność kodu bajtowego. Jeśli inżynierowie z Oracle zmienią podstawową implementację Lambda w nowszej wersji JVM, Lambdas skompilowany na starszej maszynie JVM skorzysta z nowszej implementacji.


Jako przykład, składnia linku jest nieaktualna. Spójrz na Lambda Expressions Java Trail, aby zobaczyć aktualną składnię.

+0

jesteś pewny '# {" Witaj, świecie! " }; 'jest poprawna składnia? Myślałem, że wyrazi się to w wyrażeniu lambda, takim jak '() ->" Hello world! ". – asgs

+0

Ah, tak. Właśnie przeczytałem komentarze @ Maurice'a. Powinieneś edytować ten post, aby odzwierciedlić najnowsze informacje. Dobrze wiedzieć, że '# {}' było jak Lambdas była wcześniej reprezentowana. – asgs

+1

@asgs Miałem mały blurb na dole, wskazując na ścieżkę Java, ale poszedłem dalej i zaktualizowałem odpowiedź, tak czy inaczej, aby użyć obecnej składni. – Brian