161 votes

Qu'est-ce qu'un "type SAM" en Java ?

En lisant la spécification Java-8, je continue à voir des références aux "types SAM". Je n'ai pas réussi à trouver une explication claire de ce que c'est.

Qu'est-ce qu'un type de SAM et quel est un exemple de scénario dans lequel il peut être utilisé ?

181voto

Brian Points 7975

Pour résumer le lien que Jon a posté 1 au cas où il tomberait en panne, "SAM" signifie "single abstract method" (méthode abstraite unique), et "SAM-type" fait référence à des interfaces telles que Runnable , Callable etc. Les expressions lambda, une nouvelle fonctionnalité de Java 8, sont considérées comme un type SAM et peuvent être librement converties en elles.

Par exemple, avec une interface comme celle-ci :

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

Vous pouvez déclarer un Callable en utilisant des expressions lambda comme ceci :

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

Dans ce contexte, les expressions lambda ne sont que du sucre syntaxique. Elles ont une meilleure apparence dans le code que les classes anonymes et sont moins restrictives sur la dénomination des méthodes. Prenez cet exemple dans le lien :

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

Cela crée un Comparator à l'aide d'une méthode spécifique qui ne porte pas le même nom que la méthode Comparator.compare De cette façon, vous n'êtes pas obligé de suivre le nommage des méthodes de l'interface et vous pouvez avoir plusieurs surcharges de comparaison dans une classe, puis créer les comparateurs à la volée via les expressions lambda.

Approfondir...

À un niveau plus profond, Java les met en œuvre à l'aide de la fonction invokedynamic instruction de bytecode ajoutée dans Java 7. J'ai dit précédemment que la déclaration d'une Lambda crée une instance de Callable o Comparable similaire à une classe anonyme, mais ce n'est pas strictement vrai. Au lieu de cela, la première fois que le invokedynamic est appelé, il crée un gestionnaire de fonction Lambda en utilisant la fonction LambdaMetafactory.metafactory méthode Il utilise ensuite cette instance en cache dans les invocations futures de la lambda. Vous trouverez plus d'informations dans cette réponse .

Cette approche est complexe et comprend même du code capable de lire des valeurs et des références primitives directement à partir de la mémoire de la pile pour les transmettre à votre code Lambda (par exemple, pour contourner la nécessité d'allouer un fichier de type Object[] pour invoquer votre Lambda), mais elle permet aux itérations futures de l'implémentation Lambda de remplacer les anciennes implémentations sans avoir à se soucier de la compatibilité du bytecode. Si les ingénieurs d'Oracle modifient l'implémentation sous-jacente de Lambda dans une nouvelle version de la JVM, les Lambda compilés sur une ancienne JVM utiliseront automatiquement la nouvelle implémentation sans aucune modification de la part du développeur.


1 La syntaxe du lien est obsolète. Jetez un coup d'œil à la Lambda Expressions Java Trail pour voir la syntaxe actuelle.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X