Per riassumere il link Jon ha postato 1 nel caso in cui va mai giù, "SAM" sta per "single metodo astratto", e "SAM-tipo" si riferisce a interfacce come Runnable
, Callable
ecc espressioni Lambda, una nuova funzionalità di Java 8, sono considerato un tipo SAM e può essere liberamente convertito in essi.
Ad esempio, con un'interfaccia come questa:
public interface Callable<T> {
public T call();
}
Puoi dichiarare Callable
usando espressioni lambda come questa:
Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"
Le espressioni lambda in questo contesto sono per lo più solo zucchero sintattico. Hanno un aspetto migliore nel codice rispetto alle classi anonime e sono meno restrittivi sulla denominazione del metodo. Prendi questo esempio dal 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);
Ciò crea l' Comparator
utilizzo di un metodo specifico che non condivide lo stesso nome di Comparator.compare
, in questo modo non è necessario seguire la denominazione dell'interfaccia dei metodi e si possono avere sostituzioni multiple di confronto in una classe, quindi creare i comparatori al volo tramite le espressioni lambda.
Più profondo ...
A un livello più profondo, Java li implementa usando l' invokedynamic
istruzione bytecode aggiunta in Java 7. Ho detto prima che dichiarare una Lambda crea un'istanza Callable
o Comparable
simile a una classe anonima, ma ciò non è strettamente vero. Invece, la prima volta che invokedynamic
viene chiamato, crea un gestore di funzioni Lambda utilizzando il LambdaMetafactory.metafactory
metodo , quindi utilizza questa istanza memorizzata nella cache in future invocazioni di Lambda. Ulteriori informazioni sono disponibili in questa risposta .
Questo approccio è complesso e include anche codice in grado di leggere valori primitivi e riferimenti direttamente dalla memoria dello stack per passare nel codice Lambda (ad esempio per aggirare la necessità di allocare un Object[]
array per invocare Lambda), ma consente future iterazioni dell'implementazione Lambda per sostituire le vecchie implementazioni senza doversi preoccupare della compatibilità con bytecode. Se gli ingegneri di Oracle modificano l'implementazione Lambda sottostante in una versione più recente di JVM, Lambdas compilata su una JVM precedente utilizzerà automaticamente l'implementazione più recente senza alcuna modifica da parte dello sviluppatore.
1 La sintassi sul collegamento non è aggiornata. Dai un'occhiata a Lambda Expressions Java Trail per vedere la sintassi corrente.