Pour résumer le lien Jon publié 1 dans le cas où il ne va jamais vers le bas, « SAM » signifie « méthode abstraite unique » et « SAM type » fait référence à des interfaces comme Runnable
, Callable
, etc. expressions Lambda, une nouvelle fonctionnalité en Java 8, sont considéré comme un type SAM et peut être librement converti en eux.
Par exemple, avec une interface comme celle-ci:
public interface Callable<T> {
public T call();
}
Vous pouvez déclarer une Callable
utilisation d'expressions lambda comme ceci:
Callable<String> strCallable = () -> "Hello world!";
System.out.println(strCallable.call()); // prints "Hello world!"
Les expressions lambda dans ce contexte ne sont pour la plupart que du sucre syntaxique. Ils ont une meilleure apparence dans le code que les classes anonymes et sont moins restrictifs sur la dénomination des méthodes. Prenez cet exemple sur 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 une Comparator
utilisation d'une méthode spécifique qui ne partage pas le même nom que Comparator.compare
, de cette façon, vous n'avez pas à suivre la dénomination de l'interface des méthodes et vous pouvez avoir plusieurs remplacements de comparaison dans une classe, puis créer les comparateurs à la volée via les expressions lambda.
Aller plus loin ...
À un niveau plus profond, Java les implémente en utilisant l' invokedynamic
instruction bytecode ajoutée dans Java 7. J'ai dit plus tôt que déclarer un Lambda crée une instance Callable
ou 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 à l'aide de la LambdaMetafactory.metafactory
méthode , puis utilise cette instance mise en cache dans les futurs appels de Lambda. Plus d'informations peuvent être trouvées dans cette réponse .
Cette approche est complexe et inclut même du code qui peut lire des valeurs primitives et des références directement à partir de la mémoire de la pile pour passer dans votre code Lambda (par exemple pour contourner le besoin d'allouer un Object[]
tableau pour appeler votre Lambda), mais elle permet de futures itérations de l'implémentation Lambda pour remplacer les anciennes implémentations sans avoir à se soucier de la compatibilité du bytecode. Si les ingénieurs d'Oracle modifient l'implémentation Lambda sous-jacente dans une version plus récente de la JVM, Lambdas compilé sur une ancienne JVM utilisera automatiquement l'implémentation la plus récente sans aucune modification de la part du développeur.
1 La syntaxe du lien est obsolète. Jetez un œil à la piste Java des expressions Lambda pour voir la syntaxe actuelle.