Che cos'è un "tipo SAM" in Java?


133

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?


4
Vedi cr.openjdk.java.net/~briangoetz/lambda/lambda-state-3.html (che ho trovato dopo una singola ricerca, che mi ha portato a un'altra domanda SO).
Jon Skeet,

2
Si prega di non indirizzare le persone a informazioni non aggiornate. Una ricerca leggermente più lunga ti avrebbe portato alla versione più aggiornata: cr.openjdk.java.net/~briangoetz/lambda/lambda-state-4.html , che a sua volta ha 18 mesi e ora è obsoleto in molti posti. Alla domanda del PO viene fornita una risposta su lambdafaq.org/what-is-a-functional-interface , una pagina di una FAQ che cerco di aggiornare in quello che è stato fino a poco tempo fa un linguaggio in rapida evoluzione e uno sviluppo delle API.
Maurice Naftalin,

1
@MauriceNaftalin Potresti anche semplicemente collegare il percorso Java , che viene aggiornato dal team di sviluppo.
Brian,

1
Il termine attuale è "interfaccia funzionale".
newacct

1
@MauriceNaftalin: Mi dispiace, ho perso quello. Sarebbe sicuramente legato ad esso se l'avessi trovato.
Jon Skeet,

Risposte:


142

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.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.