Leggendo le specifiche Java-8, continuo a vedere riferimenti ai "tipi SAM". Non sono stato in grado di trovare una chiara spiegazione di cosa si tratti.
Che cos'è un tipo SAM e qual è uno scenario esemplificativo di quando uno potrebbe essere usato?
Leggendo le specifiche Java-8, continuo a vedere riferimenti ai "tipi SAM". Non sono stato in grado di trovare una chiara spiegazione di cosa si tratti.
Che cos'è un tipo SAM e qual è uno scenario esemplificativo di quando uno potrebbe essere usato?
Risposte:
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, Callableecc 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 Callableusando 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' Comparatorutilizzo 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' invokedynamicistruzione bytecode aggiunta in Java 7. Ho detto prima che dichiarare una Lambda crea un'istanza Callableo Comparablesimile a una classe anonima, ma ciò non è strettamente vero. Invece, la prima volta che invokedynamicviene chiamato, crea un gestore di funzioni Lambda utilizzando il LambdaMetafactory.metafactorymetodo , 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.